firebase-tools 14.5.1 → 14.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/commands/projects-create.js +1 -1
- package/lib/commands/use.js +4 -1
- package/lib/dataconnect/client.js +1 -0
- package/lib/deploy/functions/checkIam.js +38 -3
- package/lib/deploy/functions/prepare.js +1 -0
- package/lib/deploy/functions/services/firestore.js +23 -4
- package/lib/emulator/auth/cloudFunctions.js +14 -1
- package/lib/emulator/dataconnect/pgliteServer.js +20 -12
- package/lib/emulator/downloadableEmulatorInfo.json +18 -18
- package/lib/firestore/delete.js +6 -4
- package/lib/frameworks/constants.js +1 -1
- package/lib/frameworks/utils.js +8 -2
- package/lib/gcp/firestore.js +26 -21
- package/lib/{gif → gemini}/fdcExperience.js +14 -13
- package/lib/init/features/dataconnect/index.js +1 -1
- package/lib/init/features/project.js +13 -6
- package/lib/management/projects.js +6 -5
- package/lib/mcp/tools/core/consult_assistant.js +1 -1
- package/lib/mcp/tools/dataconnect/generate_operation.js +1 -1
- package/lib/mcp/tools/dataconnect/generate_schema.js +1 -1
- package/lib/mcp/tools/firestore/delete_document.js +17 -4
- package/lib/mcp/tools/firestore/emulator.js +16 -0
- package/lib/mcp/tools/firestore/get_documents.js +12 -2
- package/lib/mcp/tools/firestore/list_collections.js +14 -3
- package/lib/mcp/tools/firestore/query_collection.js +12 -2
- package/package.json +3 -2
- package/lib/emulator/dataconnect/pg-gateway/auth/base-auth-flow.js +0 -11
- package/lib/emulator/dataconnect/pg-gateway/auth/cert.js +0 -69
- package/lib/emulator/dataconnect/pg-gateway/auth/index.js +0 -22
- package/lib/emulator/dataconnect/pg-gateway/auth/md5.js +0 -135
- package/lib/emulator/dataconnect/pg-gateway/auth/password.js +0 -65
- package/lib/emulator/dataconnect/pg-gateway/auth/sasl/sasl-mechanism.js +0 -34
- package/lib/emulator/dataconnect/pg-gateway/auth/sasl/scram-sha-256.js +0 -298
- package/lib/emulator/dataconnect/pg-gateway/backend-error.js +0 -75
- package/lib/emulator/dataconnect/pg-gateway/buffer-reader.js +0 -55
- package/lib/emulator/dataconnect/pg-gateway/buffer-writer.js +0 -79
- package/lib/emulator/dataconnect/pg-gateway/connection.js +0 -419
- package/lib/emulator/dataconnect/pg-gateway/connection.types.js +0 -8
- package/lib/emulator/dataconnect/pg-gateway/crypto.js +0 -40
- package/lib/emulator/dataconnect/pg-gateway/duplex.js +0 -53
- package/lib/emulator/dataconnect/pg-gateway/index.js +0 -27
- package/lib/emulator/dataconnect/pg-gateway/message-buffer.js +0 -96
- package/lib/emulator/dataconnect/pg-gateway/message-codes.js +0 -54
- package/lib/emulator/dataconnect/pg-gateway/platforms/node/index.js +0 -13
- package/lib/emulator/dataconnect/pg-gateway/polyfills/readable-stream-async-iterator.js +0 -36
- package/lib/emulator/dataconnect/pg-gateway/utils.js +0 -40
- /package/lib/{emulator/dataconnect/pg-gateway/auth/trust.js → gemini/types.js} +0 -0
|
@@ -20,8 +20,9 @@ var ProjectParentResourceType;
|
|
|
20
20
|
ProjectParentResourceType["ORGANIZATION"] = "organization";
|
|
21
21
|
ProjectParentResourceType["FOLDER"] = "folder";
|
|
22
22
|
})(ProjectParentResourceType = exports.ProjectParentResourceType || (exports.ProjectParentResourceType = {}));
|
|
23
|
-
async function promptProjectCreation() {
|
|
24
|
-
|
|
23
|
+
async function promptProjectCreation(options) {
|
|
24
|
+
var _a, _b;
|
|
25
|
+
const projectId = (_a = options.projectId) !== null && _a !== void 0 ? _a : (await prompt.input({
|
|
25
26
|
message: "Please specify a unique project id " +
|
|
26
27
|
`(${clc.yellow("warning")}: cannot be modified afterward) [6-30 characters]:\n`,
|
|
27
28
|
validate: (projectId) => {
|
|
@@ -35,8 +36,8 @@ async function promptProjectCreation() {
|
|
|
35
36
|
return true;
|
|
36
37
|
}
|
|
37
38
|
},
|
|
38
|
-
});
|
|
39
|
-
const displayName = await prompt.input({
|
|
39
|
+
}));
|
|
40
|
+
const displayName = (_b = options.displayName) !== null && _b !== void 0 ? _b : (await prompt.input({
|
|
40
41
|
default: projectId,
|
|
41
42
|
message: "What would you like to call your project? (defaults to your project ID)",
|
|
42
43
|
validate: (displayName) => {
|
|
@@ -50,7 +51,7 @@ async function promptProjectCreation() {
|
|
|
50
51
|
return true;
|
|
51
52
|
}
|
|
52
53
|
},
|
|
53
|
-
});
|
|
54
|
+
}));
|
|
54
55
|
return { projectId, displayName };
|
|
55
56
|
}
|
|
56
57
|
exports.promptProjectCreation = promptProjectCreation;
|
|
@@ -4,7 +4,7 @@ exports.consult_assistant = void 0;
|
|
|
4
4
|
const zod_1 = require("zod");
|
|
5
5
|
const tool_js_1 = require("../../tool.js");
|
|
6
6
|
const util_js_1 = require("../../util.js");
|
|
7
|
-
const fdcExperience_js_1 = require("../../../
|
|
7
|
+
const fdcExperience_js_1 = require("../../../gemini/fdcExperience.js");
|
|
8
8
|
exports.consult_assistant = (0, tool_js_1.tool)({
|
|
9
9
|
name: "consult_assistant",
|
|
10
10
|
description: "Send a question to an AI assistant specifically enhanced to answer Firebase questions.",
|
|
@@ -4,7 +4,7 @@ exports.generate_operation = void 0;
|
|
|
4
4
|
const zod_1 = require("zod");
|
|
5
5
|
const tool_js_1 = require("../../tool.js");
|
|
6
6
|
const util_js_1 = require("../../util.js");
|
|
7
|
-
const fdcExperience_js_1 = require("../../../
|
|
7
|
+
const fdcExperience_js_1 = require("../../../gemini/fdcExperience.js");
|
|
8
8
|
const fileUtils_js_1 = require("../../../dataconnect/fileUtils.js");
|
|
9
9
|
exports.generate_operation = (0, tool_js_1.tool)({
|
|
10
10
|
name: "generate_operation",
|
|
@@ -4,7 +4,7 @@ exports.generate_schema = void 0;
|
|
|
4
4
|
const zod_1 = require("zod");
|
|
5
5
|
const tool_js_1 = require("../../tool.js");
|
|
6
6
|
const util_js_1 = require("../../util.js");
|
|
7
|
-
const fdcExperience_js_1 = require("../../../
|
|
7
|
+
const fdcExperience_js_1 = require("../../../gemini/fdcExperience.js");
|
|
8
8
|
exports.generate_schema = (0, tool_js_1.tool)({
|
|
9
9
|
name: "generate_schema",
|
|
10
10
|
description: "Generates a Firebase Data Connect Schema based on the users description of an app.",
|
|
@@ -6,13 +6,19 @@ const tool_js_1 = require("../../tool.js");
|
|
|
6
6
|
const util_js_1 = require("../../util.js");
|
|
7
7
|
const firestore_js_1 = require("../../../gcp/firestore.js");
|
|
8
8
|
const delete_js_1 = require("../../../firestore/delete.js");
|
|
9
|
+
const emulator_js_1 = require("./emulator.js");
|
|
9
10
|
exports.delete_document = (0, tool_js_1.tool)({
|
|
10
11
|
name: "delete_document",
|
|
11
12
|
description: "Deletes a Firestore documents from a database in the current project by full document paths. Use this if you know the exact path of a document.",
|
|
12
13
|
inputSchema: zod_1.z.object({
|
|
14
|
+
database: zod_1.z
|
|
15
|
+
.string()
|
|
16
|
+
.optional()
|
|
17
|
+
.describe("Database id to use. Defaults to `(default)` if unspecified."),
|
|
13
18
|
path: zod_1.z
|
|
14
19
|
.string()
|
|
15
20
|
.describe("A document path (e.g. `collectionName/documentId` or `parentCollection/parentDocument/collectionName/documentId`)"),
|
|
21
|
+
use_emulator: zod_1.z.boolean().default(false).describe("Target the Firestore emulator if true."),
|
|
16
22
|
}),
|
|
17
23
|
annotations: {
|
|
18
24
|
title: "Delete Firestore document",
|
|
@@ -22,14 +28,21 @@ exports.delete_document = (0, tool_js_1.tool)({
|
|
|
22
28
|
requiresAuth: true,
|
|
23
29
|
requiresProject: true,
|
|
24
30
|
},
|
|
25
|
-
}, async ({ path }, { projectId }) => {
|
|
26
|
-
|
|
31
|
+
}, async ({ path, database, use_emulator }, { projectId, host }) => {
|
|
32
|
+
let emulatorUrl;
|
|
33
|
+
if (use_emulator) {
|
|
34
|
+
emulatorUrl = await (0, emulator_js_1.getFirestoreEmulatorUrl)(await host.getEmulatorHubClient());
|
|
35
|
+
}
|
|
36
|
+
const { documents, missing } = await (0, firestore_js_1.getDocuments)(projectId, [path], database, emulatorUrl);
|
|
27
37
|
if (missing.length > 0 && documents && documents.length === 0) {
|
|
28
38
|
return (0, util_js_1.mcpError)(`None of the specified documents were found in project '${projectId}'`);
|
|
29
39
|
}
|
|
30
|
-
const firestoreDelete = new delete_js_1.FirestoreDelete(projectId, path, {
|
|
40
|
+
const firestoreDelete = new delete_js_1.FirestoreDelete(projectId, path, {
|
|
41
|
+
databaseId: database !== null && database !== void 0 ? database : "(default)",
|
|
42
|
+
urlPrefix: emulatorUrl,
|
|
43
|
+
});
|
|
31
44
|
await firestoreDelete.execute();
|
|
32
|
-
const { documents: postDeleteDocuments, missing: postDeleteMissing } = await (0, firestore_js_1.getDocuments)(projectId, [path]);
|
|
45
|
+
const { documents: postDeleteDocuments, missing: postDeleteMissing } = await (0, firestore_js_1.getDocuments)(projectId, [path], emulatorUrl);
|
|
33
46
|
if (postDeleteMissing.length > 0 && postDeleteDocuments.length === 0) {
|
|
34
47
|
return (0, util_js_1.toContent)(`Successfully removed document located at : ${path}`);
|
|
35
48
|
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.getFirestoreEmulatorUrl = void 0;
|
|
4
|
+
const types_js_1 = require("../../../emulator/types.js");
|
|
5
|
+
async function getFirestoreEmulatorUrl(hubClient) {
|
|
6
|
+
if (!hubClient) {
|
|
7
|
+
throw Error("Emulator Hub not found or is not running. You can start the emulator by running `firebase emulators:start` in your firebase project directory.");
|
|
8
|
+
}
|
|
9
|
+
const emulators = await hubClient.getEmulators();
|
|
10
|
+
const firestoreEmulatorInfo = emulators[types_js_1.Emulators.FIRESTORE];
|
|
11
|
+
if (!firestoreEmulatorInfo) {
|
|
12
|
+
throw Error("No Firestore Emulator found running. Make sure your project firebase.json file includes firestore and then rerun emulator using `firebase emulators:start` from your project directory.");
|
|
13
|
+
}
|
|
14
|
+
return `http://${firestoreEmulatorInfo.host}:${firestoreEmulatorInfo.port}`;
|
|
15
|
+
}
|
|
16
|
+
exports.getFirestoreEmulatorUrl = getFirestoreEmulatorUrl;
|
|
@@ -6,13 +6,19 @@ const tool_js_1 = require("../../tool.js");
|
|
|
6
6
|
const util_js_1 = require("../../util.js");
|
|
7
7
|
const firestore_js_1 = require("../../../gcp/firestore.js");
|
|
8
8
|
const converter_js_1 = require("./converter.js");
|
|
9
|
+
const emulator_js_1 = require("./emulator.js");
|
|
9
10
|
exports.get_documents = (0, tool_js_1.tool)({
|
|
10
11
|
name: "get_documents",
|
|
11
12
|
description: "Retrieves one or more Firestore documents from a database in the current project by full document paths. Use this if you know the exact path of a document.",
|
|
12
13
|
inputSchema: zod_1.z.object({
|
|
14
|
+
database: zod_1.z
|
|
15
|
+
.string()
|
|
16
|
+
.optional()
|
|
17
|
+
.describe("Database id to use. Defaults to `(default)` if unspecified."),
|
|
13
18
|
paths: zod_1.z
|
|
14
19
|
.array(zod_1.z.string())
|
|
15
20
|
.describe("One or more document paths (e.g. `collectionName/documentId` or `parentCollection/parentDocument/collectionName/documentId`)"),
|
|
21
|
+
use_emulator: zod_1.z.boolean().default(false).describe("Target the Firestore emulator if true."),
|
|
16
22
|
}),
|
|
17
23
|
annotations: {
|
|
18
24
|
title: "Get Firestore documents",
|
|
@@ -22,10 +28,14 @@ exports.get_documents = (0, tool_js_1.tool)({
|
|
|
22
28
|
requiresAuth: true,
|
|
23
29
|
requiresProject: true,
|
|
24
30
|
},
|
|
25
|
-
}, async ({ paths }, { projectId }) => {
|
|
31
|
+
}, async ({ paths, database, use_emulator }, { projectId, host }) => {
|
|
26
32
|
if (!paths || !paths.length)
|
|
27
33
|
return (0, util_js_1.mcpError)("Must supply at least one document path.");
|
|
28
|
-
|
|
34
|
+
let emulatorUrl;
|
|
35
|
+
if (use_emulator) {
|
|
36
|
+
emulatorUrl = await (0, emulator_js_1.getFirestoreEmulatorUrl)(await host.getEmulatorHubClient());
|
|
37
|
+
}
|
|
38
|
+
const { documents, missing } = await (0, firestore_js_1.getDocuments)(projectId, paths, database, emulatorUrl);
|
|
29
39
|
if (missing.length > 0 && documents && documents.length === 0) {
|
|
30
40
|
return (0, util_js_1.mcpError)(`None of the specified documents were found in project '${projectId}'`);
|
|
31
41
|
}
|
|
@@ -6,10 +6,17 @@ const tool_js_1 = require("../../tool.js");
|
|
|
6
6
|
const util_js_1 = require("../../util.js");
|
|
7
7
|
const firestore_js_1 = require("../../../gcp/firestore.js");
|
|
8
8
|
const errors_js_1 = require("../../errors.js");
|
|
9
|
+
const emulator_js_1 = require("./emulator.js");
|
|
9
10
|
exports.list_collections = (0, tool_js_1.tool)({
|
|
10
11
|
name: "list_collections",
|
|
11
12
|
description: "Retrieves a list of collections from a Firestore database in the current project.",
|
|
12
|
-
inputSchema: zod_1.z.object({
|
|
13
|
+
inputSchema: zod_1.z.object({
|
|
14
|
+
database: zod_1.z
|
|
15
|
+
.string()
|
|
16
|
+
.optional()
|
|
17
|
+
.describe("Database id to use. Defaults to `(default)` if unspecified."),
|
|
18
|
+
use_emulator: zod_1.z.boolean().default(false).describe("Target the Firestore emulator if true."),
|
|
19
|
+
}),
|
|
13
20
|
annotations: {
|
|
14
21
|
title: "List Firestore collections",
|
|
15
22
|
readOnlyHint: true,
|
|
@@ -18,8 +25,12 @@ exports.list_collections = (0, tool_js_1.tool)({
|
|
|
18
25
|
requiresAuth: true,
|
|
19
26
|
requiresProject: true,
|
|
20
27
|
},
|
|
21
|
-
}, async (
|
|
28
|
+
}, async ({ database, use_emulator }, { projectId, host }) => {
|
|
29
|
+
let emulatorUrl;
|
|
30
|
+
if (use_emulator) {
|
|
31
|
+
emulatorUrl = await (0, emulator_js_1.getFirestoreEmulatorUrl)(await host.getEmulatorHubClient());
|
|
32
|
+
}
|
|
22
33
|
if (!projectId)
|
|
23
34
|
return errors_js_1.NO_PROJECT_ERROR;
|
|
24
|
-
return (0, util_js_1.toContent)(await (0, firestore_js_1.listCollectionIds)(projectId));
|
|
35
|
+
return (0, util_js_1.toContent)(await (0, firestore_js_1.listCollectionIds)(projectId, database, emulatorUrl));
|
|
25
36
|
});
|
|
@@ -6,10 +6,15 @@ const tool_js_1 = require("../../tool.js");
|
|
|
6
6
|
const util_js_1 = require("../../util.js");
|
|
7
7
|
const firestore_js_1 = require("../../../gcp/firestore.js");
|
|
8
8
|
const converter_js_1 = require("./converter.js");
|
|
9
|
+
const emulator_js_1 = require("./emulator.js");
|
|
9
10
|
exports.query_collection = (0, tool_js_1.tool)({
|
|
10
11
|
name: "query_collection",
|
|
11
12
|
description: "Retrieves one or more Firestore documents from a collection is a database in the current project by a collection with a full document path. Use this if you know the exact path of a collection and the filtering clause you would like for the document.",
|
|
12
13
|
inputSchema: zod_1.z.object({
|
|
14
|
+
database: zod_1.z
|
|
15
|
+
.string()
|
|
16
|
+
.optional()
|
|
17
|
+
.describe("Database id to use. Defaults to `(default)` if unspecified."),
|
|
13
18
|
collection_path: zod_1.z
|
|
14
19
|
.string()
|
|
15
20
|
.describe("A collection path (e.g. `collectionName/` or `parentCollection/parentDocument/collectionName`)"),
|
|
@@ -65,6 +70,7 @@ exports.query_collection = (0, tool_js_1.tool)({
|
|
|
65
70
|
.number()
|
|
66
71
|
.describe("The maximum amount of records to return. Default is 10.")
|
|
67
72
|
.optional(),
|
|
73
|
+
use_emulator: zod_1.z.boolean().default(false).describe("Target the Firestore emulator if true."),
|
|
68
74
|
}),
|
|
69
75
|
annotations: {
|
|
70
76
|
title: "Query Firestore collection",
|
|
@@ -74,7 +80,7 @@ exports.query_collection = (0, tool_js_1.tool)({
|
|
|
74
80
|
requiresAuth: true,
|
|
75
81
|
requiresProject: true,
|
|
76
82
|
},
|
|
77
|
-
}, async ({ collection_path, filters, order, limit }, { projectId }) => {
|
|
83
|
+
}, async ({ collection_path, filters, order, limit, database, use_emulator }, { projectId, host }) => {
|
|
78
84
|
if (!collection_path || !collection_path.length)
|
|
79
85
|
return (0, util_js_1.mcpError)("Must supply at least one collection path.");
|
|
80
86
|
const structuredQuery = {
|
|
@@ -115,7 +121,11 @@ exports.query_collection = (0, tool_js_1.tool)({
|
|
|
115
121
|
];
|
|
116
122
|
}
|
|
117
123
|
structuredQuery.limit = limit ? limit : 10;
|
|
118
|
-
|
|
124
|
+
let emulatorUrl;
|
|
125
|
+
if (use_emulator) {
|
|
126
|
+
emulatorUrl = await (0, emulator_js_1.getFirestoreEmulatorUrl)(await host.getEmulatorHubClient());
|
|
127
|
+
}
|
|
128
|
+
const { documents } = await (0, firestore_js_1.queryCollection)(projectId, structuredQuery, database, emulatorUrl);
|
|
119
129
|
const docs = documents.map(converter_js_1.firestoreDocumentToJson);
|
|
120
130
|
const docsContent = (0, util_js_1.toContent)(docs);
|
|
121
131
|
return docsContent;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "firebase-tools",
|
|
3
|
-
"version": "14.
|
|
3
|
+
"version": "14.6.0",
|
|
4
4
|
"description": "Command-Line Interface for Firebase",
|
|
5
5
|
"main": "./lib/index.js",
|
|
6
6
|
"bin": {
|
|
@@ -60,7 +60,7 @@
|
|
|
60
60
|
]
|
|
61
61
|
},
|
|
62
62
|
"dependencies": {
|
|
63
|
-
"@electric-sql/pglite": "^0.2.
|
|
63
|
+
"@electric-sql/pglite": "^0.2.17",
|
|
64
64
|
"@google-cloud/cloud-sql-connector": "^1.3.3",
|
|
65
65
|
"@google-cloud/pubsub": "^4.5.0",
|
|
66
66
|
"@inquirer/prompts": "^7.4.0",
|
|
@@ -109,6 +109,7 @@
|
|
|
109
109
|
"ora": "^5.4.1",
|
|
110
110
|
"p-limit": "^3.0.1",
|
|
111
111
|
"pg": "^8.11.3",
|
|
112
|
+
"pg-gateway": "^0.3.0-beta.4",
|
|
112
113
|
"portfinder": "^1.0.32",
|
|
113
114
|
"progress": "^2.0.3",
|
|
114
115
|
"proxy-agent": "^6.3.0",
|
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.BaseAuthFlow = void 0;
|
|
4
|
-
class BaseAuthFlow {
|
|
5
|
-
constructor(params) {
|
|
6
|
-
this.reader = params.reader;
|
|
7
|
-
this.writer = params.writer;
|
|
8
|
-
this.connectionState = params.connectionState;
|
|
9
|
-
}
|
|
10
|
-
}
|
|
11
|
-
exports.BaseAuthFlow = BaseAuthFlow;
|
|
@@ -1,69 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __await = (this && this.__await) || function (v) { return this instanceof __await ? (this.v = v, this) : new __await(v); }
|
|
3
|
-
var __asyncGenerator = (this && this.__asyncGenerator) || function (thisArg, _arguments, generator) {
|
|
4
|
-
if (!Symbol.asyncIterator) throw new TypeError("Symbol.asyncIterator is not defined.");
|
|
5
|
-
var g = generator.apply(thisArg, _arguments || []), i, q = [];
|
|
6
|
-
return i = {}, verb("next"), verb("throw"), verb("return"), i[Symbol.asyncIterator] = function () { return this; }, i;
|
|
7
|
-
function verb(n) { if (g[n]) i[n] = function (v) { return new Promise(function (a, b) { q.push([n, v, a, b]) > 1 || resume(n, v); }); }; }
|
|
8
|
-
function resume(n, v) { try { step(g[n](v)); } catch (e) { settle(q[0][3], e); } }
|
|
9
|
-
function step(r) { r.value instanceof __await ? Promise.resolve(r.value.v).then(fulfill, reject) : settle(q[0][2], r); }
|
|
10
|
-
function fulfill(value) { resume("next", value); }
|
|
11
|
-
function reject(value) { resume("throw", value); }
|
|
12
|
-
function settle(f, v) { if (f(v), q.shift(), q.length) resume(q[0][0], q[0][1]); }
|
|
13
|
-
};
|
|
14
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
|
-
exports.CertAuthFlow = void 0;
|
|
16
|
-
const backend_error_1 = require("../backend-error");
|
|
17
|
-
const base_auth_flow_1 = require("./base-auth-flow");
|
|
18
|
-
const connection_1 = require("../connection");
|
|
19
|
-
class CertAuthFlow extends base_auth_flow_1.BaseAuthFlow {
|
|
20
|
-
constructor(params) {
|
|
21
|
-
var _a;
|
|
22
|
-
super(params);
|
|
23
|
-
this.completed = false;
|
|
24
|
-
this.auth = Object.assign(Object.assign({}, params.auth), { validateCredentials: (_a = params.auth.validateCredentials) !== null && _a !== void 0 ? _a : (async ({ username, certificate }) => {
|
|
25
|
-
return certificate.subject.CN === username;
|
|
26
|
-
}) });
|
|
27
|
-
this.username = params.username;
|
|
28
|
-
}
|
|
29
|
-
handleClientMessage(message) {
|
|
30
|
-
return __asyncGenerator(this, arguments, function* handleClientMessage_1() {
|
|
31
|
-
if (false) {
|
|
32
|
-
yield yield __await((0, backend_error_1.createBackendErrorMessage)({
|
|
33
|
-
severity: 'FATAL',
|
|
34
|
-
code: '08000',
|
|
35
|
-
message: `ssl connection required when auth mode is 'certificate'`,
|
|
36
|
-
}));
|
|
37
|
-
yield yield __await(connection_1.closeSignal);
|
|
38
|
-
return yield __await(void 0);
|
|
39
|
-
}
|
|
40
|
-
if (false) {
|
|
41
|
-
yield yield __await((0, backend_error_1.createBackendErrorMessage)({
|
|
42
|
-
severity: 'FATAL',
|
|
43
|
-
code: '08000',
|
|
44
|
-
message: 'client certificate is invalid',
|
|
45
|
-
}));
|
|
46
|
-
yield yield __await(connection_1.closeSignal);
|
|
47
|
-
return yield __await(void 0);
|
|
48
|
-
}
|
|
49
|
-
const isValid = false;
|
|
50
|
-
if (!isValid) {
|
|
51
|
-
yield yield __await((0, backend_error_1.createBackendErrorMessage)({
|
|
52
|
-
severity: 'FATAL',
|
|
53
|
-
code: '08000',
|
|
54
|
-
message: 'client certificate is invalid',
|
|
55
|
-
}));
|
|
56
|
-
yield yield __await(connection_1.closeSignal);
|
|
57
|
-
return yield __await(void 0);
|
|
58
|
-
}
|
|
59
|
-
this.completed = true;
|
|
60
|
-
});
|
|
61
|
-
}
|
|
62
|
-
createInitialAuthMessage() {
|
|
63
|
-
return undefined;
|
|
64
|
-
}
|
|
65
|
-
get isCompleted() {
|
|
66
|
-
return this.completed;
|
|
67
|
-
}
|
|
68
|
-
}
|
|
69
|
-
exports.CertAuthFlow = CertAuthFlow;
|
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.createAuthFlow = void 0;
|
|
4
|
-
const cert_1 = require("./cert");
|
|
5
|
-
const md5_1 = require("./md5");
|
|
6
|
-
const password_1 = require("./password");
|
|
7
|
-
const scram_sha_256_1 = require("./sasl/scram-sha-256");
|
|
8
|
-
function createAuthFlow(options) {
|
|
9
|
-
switch (options.auth.method) {
|
|
10
|
-
case 'password':
|
|
11
|
-
return new password_1.PasswordAuthFlow(Object.assign(Object.assign({}, options), { auth: options.auth }));
|
|
12
|
-
case 'md5':
|
|
13
|
-
return new md5_1.Md5AuthFlow(Object.assign(Object.assign({}, options), { auth: options.auth }));
|
|
14
|
-
case 'scram-sha-256':
|
|
15
|
-
return new scram_sha_256_1.ScramSha256AuthFlow(Object.assign(Object.assign({}, options), { auth: options.auth }));
|
|
16
|
-
case 'cert':
|
|
17
|
-
return new cert_1.CertAuthFlow(Object.assign(Object.assign({}, options), { auth: options.auth }));
|
|
18
|
-
default:
|
|
19
|
-
throw new Error(`Unsupported auth method: ${options.auth.method}`);
|
|
20
|
-
}
|
|
21
|
-
}
|
|
22
|
-
exports.createAuthFlow = createAuthFlow;
|
|
@@ -1,135 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __await = (this && this.__await) || function (v) { return this instanceof __await ? (this.v = v, this) : new __await(v); }
|
|
3
|
-
var __asyncGenerator = (this && this.__asyncGenerator) || function (thisArg, _arguments, generator) {
|
|
4
|
-
if (!Symbol.asyncIterator) throw new TypeError("Symbol.asyncIterator is not defined.");
|
|
5
|
-
var g = generator.apply(thisArg, _arguments || []), i, q = [];
|
|
6
|
-
return i = {}, verb("next"), verb("throw"), verb("return"), i[Symbol.asyncIterator] = function () { return this; }, i;
|
|
7
|
-
function verb(n) { if (g[n]) i[n] = function (v) { return new Promise(function (a, b) { q.push([n, v, a, b]) > 1 || resume(n, v); }); }; }
|
|
8
|
-
function resume(n, v) { try { step(g[n](v)); } catch (e) { settle(q[0][3], e); } }
|
|
9
|
-
function step(r) { r.value instanceof __await ? Promise.resolve(r.value.v).then(fulfill, reject) : settle(q[0][2], r); }
|
|
10
|
-
function fulfill(value) { resume("next", value); }
|
|
11
|
-
function reject(value) { resume("throw", value); }
|
|
12
|
-
function settle(f, v) { if (f(v), q.shift(), q.length) resume(q[0][0], q[0][1]); }
|
|
13
|
-
};
|
|
14
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
|
-
exports.validateBinaryLike = exports.encodeHex = exports.concat = exports.createPreHashedPassword = exports.generateMd5Salt = exports.md5 = exports.hashPreHashedPassword = exports.Md5AuthFlow = void 0;
|
|
16
|
-
const backend_error_1 = require("../backend-error");
|
|
17
|
-
const connection_1 = require("../connection");
|
|
18
|
-
const message_codes_1 = require("../message-codes");
|
|
19
|
-
const base_auth_flow_1 = require("./base-auth-flow");
|
|
20
|
-
class Md5AuthFlow extends base_auth_flow_1.BaseAuthFlow {
|
|
21
|
-
constructor(params) {
|
|
22
|
-
var _a;
|
|
23
|
-
super(params);
|
|
24
|
-
this.completed = false;
|
|
25
|
-
this.auth = Object.assign(Object.assign({}, params.auth), { validateCredentials: (_a = params.auth.validateCredentials) !== null && _a !== void 0 ? _a : (async ({ preHashedPassword, hashedPassword, salt }) => {
|
|
26
|
-
const expectedHashedPassword = await hashPreHashedPassword(preHashedPassword, salt);
|
|
27
|
-
return hashedPassword === expectedHashedPassword;
|
|
28
|
-
}) });
|
|
29
|
-
this.username = params.username;
|
|
30
|
-
this.salt = generateMd5Salt();
|
|
31
|
-
}
|
|
32
|
-
handleClientMessage(message) {
|
|
33
|
-
return __asyncGenerator(this, arguments, function* handleClientMessage_1() {
|
|
34
|
-
const length = this.reader.int32();
|
|
35
|
-
const hashedPassword = this.reader.cstring();
|
|
36
|
-
const preHashedPassword = yield __await(this.auth.getPreHashedPassword({
|
|
37
|
-
username: this.username,
|
|
38
|
-
}, this.connectionState));
|
|
39
|
-
const isValid = yield __await(this.auth.validateCredentials({
|
|
40
|
-
username: this.username,
|
|
41
|
-
hashedPassword,
|
|
42
|
-
preHashedPassword,
|
|
43
|
-
salt: this.salt,
|
|
44
|
-
}, this.connectionState));
|
|
45
|
-
if (!isValid) {
|
|
46
|
-
yield yield __await((0, backend_error_1.createBackendErrorMessage)({
|
|
47
|
-
severity: 'FATAL',
|
|
48
|
-
code: '28P01',
|
|
49
|
-
message: `password authentication failed for user "${this.username}"`,
|
|
50
|
-
}));
|
|
51
|
-
yield yield __await(connection_1.closeSignal);
|
|
52
|
-
return yield __await(void 0);
|
|
53
|
-
}
|
|
54
|
-
this.completed = true;
|
|
55
|
-
});
|
|
56
|
-
}
|
|
57
|
-
createInitialAuthMessage() {
|
|
58
|
-
return this.createAuthenticationMD5Password();
|
|
59
|
-
}
|
|
60
|
-
get isCompleted() {
|
|
61
|
-
return this.completed;
|
|
62
|
-
}
|
|
63
|
-
createAuthenticationMD5Password() {
|
|
64
|
-
this.writer.addInt32(5);
|
|
65
|
-
this.writer.add(Buffer.from(this.salt));
|
|
66
|
-
return this.writer.flush(message_codes_1.BackendMessageCode.AuthenticationResponse);
|
|
67
|
-
}
|
|
68
|
-
}
|
|
69
|
-
exports.Md5AuthFlow = Md5AuthFlow;
|
|
70
|
-
async function hashPreHashedPassword(preHashedPassword, salt) {
|
|
71
|
-
const hash = await md5(concat([
|
|
72
|
-
new TextEncoder().encode(preHashedPassword),
|
|
73
|
-
salt instanceof ArrayBuffer
|
|
74
|
-
? new Uint8Array(salt)
|
|
75
|
-
: new Uint8Array(salt.buffer, salt.byteOffset, salt.byteLength),
|
|
76
|
-
]));
|
|
77
|
-
return `md5${hash}`;
|
|
78
|
-
}
|
|
79
|
-
exports.hashPreHashedPassword = hashPreHashedPassword;
|
|
80
|
-
async function md5(value) {
|
|
81
|
-
const hash = await crypto.subtle.digest('MD5', typeof value === 'string' ? new TextEncoder().encode(value) : value);
|
|
82
|
-
return encodeHex(hash);
|
|
83
|
-
}
|
|
84
|
-
exports.md5 = md5;
|
|
85
|
-
function generateMd5Salt() {
|
|
86
|
-
const salt = new Uint8Array(4);
|
|
87
|
-
crypto.getRandomValues(salt);
|
|
88
|
-
return salt;
|
|
89
|
-
}
|
|
90
|
-
exports.generateMd5Salt = generateMd5Salt;
|
|
91
|
-
async function createPreHashedPassword(username, password) {
|
|
92
|
-
return await md5(`${password}${username}`);
|
|
93
|
-
}
|
|
94
|
-
exports.createPreHashedPassword = createPreHashedPassword;
|
|
95
|
-
function concat(buffers) {
|
|
96
|
-
let length = 0;
|
|
97
|
-
for (const buffer of buffers) {
|
|
98
|
-
length += buffer.length;
|
|
99
|
-
}
|
|
100
|
-
const output = new Uint8Array(length);
|
|
101
|
-
let index = 0;
|
|
102
|
-
for (const buffer of buffers) {
|
|
103
|
-
output.set(buffer, index);
|
|
104
|
-
index += buffer.length;
|
|
105
|
-
}
|
|
106
|
-
return output;
|
|
107
|
-
}
|
|
108
|
-
exports.concat = concat;
|
|
109
|
-
const hexTable = new TextEncoder().encode("0123456789abcdef");
|
|
110
|
-
const textEncoder = new TextEncoder();
|
|
111
|
-
const textDecoder = new TextDecoder();
|
|
112
|
-
function encodeHex(src) {
|
|
113
|
-
const u8 = validateBinaryLike(src);
|
|
114
|
-
const dst = new Uint8Array(u8.length * 2);
|
|
115
|
-
for (let i = 0; i < u8.length; i++) {
|
|
116
|
-
const v = u8[i];
|
|
117
|
-
dst[i * 2] = hexTable[v >> 4];
|
|
118
|
-
dst[i * 2 + 1] = hexTable[v & 0x0f];
|
|
119
|
-
}
|
|
120
|
-
return textDecoder.decode(dst);
|
|
121
|
-
}
|
|
122
|
-
exports.encodeHex = encodeHex;
|
|
123
|
-
function validateBinaryLike(source) {
|
|
124
|
-
if (typeof source === "string") {
|
|
125
|
-
return textEncoder.encode(source);
|
|
126
|
-
}
|
|
127
|
-
else if (source instanceof Uint8Array) {
|
|
128
|
-
return source;
|
|
129
|
-
}
|
|
130
|
-
else if (source instanceof ArrayBuffer) {
|
|
131
|
-
return new Uint8Array(source);
|
|
132
|
-
}
|
|
133
|
-
throw new TypeError(`Cannot validate the input as it must be a Uint8Array, a string, or an ArrayBuffer`);
|
|
134
|
-
}
|
|
135
|
-
exports.validateBinaryLike = validateBinaryLike;
|
|
@@ -1,65 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __await = (this && this.__await) || function (v) { return this instanceof __await ? (this.v = v, this) : new __await(v); }
|
|
3
|
-
var __asyncGenerator = (this && this.__asyncGenerator) || function (thisArg, _arguments, generator) {
|
|
4
|
-
if (!Symbol.asyncIterator) throw new TypeError("Symbol.asyncIterator is not defined.");
|
|
5
|
-
var g = generator.apply(thisArg, _arguments || []), i, q = [];
|
|
6
|
-
return i = {}, verb("next"), verb("throw"), verb("return"), i[Symbol.asyncIterator] = function () { return this; }, i;
|
|
7
|
-
function verb(n) { if (g[n]) i[n] = function (v) { return new Promise(function (a, b) { q.push([n, v, a, b]) > 1 || resume(n, v); }); }; }
|
|
8
|
-
function resume(n, v) { try { step(g[n](v)); } catch (e) { settle(q[0][3], e); } }
|
|
9
|
-
function step(r) { r.value instanceof __await ? Promise.resolve(r.value.v).then(fulfill, reject) : settle(q[0][2], r); }
|
|
10
|
-
function fulfill(value) { resume("next", value); }
|
|
11
|
-
function reject(value) { resume("throw", value); }
|
|
12
|
-
function settle(f, v) { if (f(v), q.shift(), q.length) resume(q[0][0], q[0][1]); }
|
|
13
|
-
};
|
|
14
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
|
-
exports.PasswordAuthFlow = void 0;
|
|
16
|
-
const backend_error_1 = require("../backend-error");
|
|
17
|
-
const connection_1 = require("../connection");
|
|
18
|
-
const message_codes_1 = require("../message-codes");
|
|
19
|
-
const base_auth_flow_1 = require("./base-auth-flow");
|
|
20
|
-
class PasswordAuthFlow extends base_auth_flow_1.BaseAuthFlow {
|
|
21
|
-
constructor(params) {
|
|
22
|
-
var _a;
|
|
23
|
-
super(params);
|
|
24
|
-
this.completed = false;
|
|
25
|
-
this.auth = Object.assign(Object.assign({}, params.auth), { validateCredentials: (_a = params.auth.validateCredentials) !== null && _a !== void 0 ? _a : (async ({ password, clearTextPassword }) => {
|
|
26
|
-
return password === clearTextPassword;
|
|
27
|
-
}) });
|
|
28
|
-
this.username = params.username;
|
|
29
|
-
}
|
|
30
|
-
handleClientMessage(message) {
|
|
31
|
-
return __asyncGenerator(this, arguments, function* handleClientMessage_1() {
|
|
32
|
-
const length = this.reader.int32();
|
|
33
|
-
const password = this.reader.cstring();
|
|
34
|
-
const clearTextPassword = yield __await(this.auth.getClearTextPassword({
|
|
35
|
-
username: this.username,
|
|
36
|
-
}, this.connectionState));
|
|
37
|
-
const isValid = yield __await(this.auth.validateCredentials({
|
|
38
|
-
username: this.username,
|
|
39
|
-
password,
|
|
40
|
-
clearTextPassword,
|
|
41
|
-
}, this.connectionState));
|
|
42
|
-
if (!isValid) {
|
|
43
|
-
yield yield __await((0, backend_error_1.createBackendErrorMessage)({
|
|
44
|
-
severity: 'FATAL',
|
|
45
|
-
code: '28P01',
|
|
46
|
-
message: `password authentication failed for user "${this.username}"`,
|
|
47
|
-
}));
|
|
48
|
-
yield yield __await(connection_1.closeSignal);
|
|
49
|
-
return yield __await(void 0);
|
|
50
|
-
}
|
|
51
|
-
this.completed = true;
|
|
52
|
-
});
|
|
53
|
-
}
|
|
54
|
-
createInitialAuthMessage() {
|
|
55
|
-
return this.createAuthenticationCleartextPassword();
|
|
56
|
-
}
|
|
57
|
-
get isCompleted() {
|
|
58
|
-
return this.completed;
|
|
59
|
-
}
|
|
60
|
-
createAuthenticationCleartextPassword() {
|
|
61
|
-
this.writer.addInt32(3);
|
|
62
|
-
return this.writer.flush(message_codes_1.BackendMessageCode.AuthenticationResponse);
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
exports.PasswordAuthFlow = PasswordAuthFlow;
|
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.SaslMechanism = void 0;
|
|
4
|
-
const message_codes_1 = require("../../message-codes");
|
|
5
|
-
const SaslMessageCode = {
|
|
6
|
-
AuthenticationSASL: 10,
|
|
7
|
-
AuthenticationSASLContinue: 11,
|
|
8
|
-
AuthenticationSASLFinal: 12,
|
|
9
|
-
};
|
|
10
|
-
class SaslMechanism {
|
|
11
|
-
constructor(params) {
|
|
12
|
-
this.writer = params.writer;
|
|
13
|
-
}
|
|
14
|
-
createAuthenticationSASL() {
|
|
15
|
-
const mechanisms = ['SCRAM-SHA-256'];
|
|
16
|
-
this.writer.addInt32(SaslMessageCode.AuthenticationSASL);
|
|
17
|
-
for (const mechanism of mechanisms) {
|
|
18
|
-
this.writer.addCString(mechanism);
|
|
19
|
-
}
|
|
20
|
-
this.writer.addCString('');
|
|
21
|
-
return this.writer.flush(message_codes_1.BackendMessageCode.AuthenticationResponse);
|
|
22
|
-
}
|
|
23
|
-
createAuthenticationSASLContinue(message) {
|
|
24
|
-
this.writer.addInt32(SaslMessageCode.AuthenticationSASLContinue);
|
|
25
|
-
this.writer.addString(message);
|
|
26
|
-
return this.writer.flush(message_codes_1.BackendMessageCode.AuthenticationResponse);
|
|
27
|
-
}
|
|
28
|
-
createAuthenticationSASLFinal(message) {
|
|
29
|
-
this.writer.addInt32(SaslMessageCode.AuthenticationSASLFinal);
|
|
30
|
-
this.writer.addString(message);
|
|
31
|
-
return this.writer.flush(message_codes_1.BackendMessageCode.AuthenticationResponse);
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
exports.SaslMechanism = SaslMechanism;
|