firebase-tools 14.5.1 → 14.7.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/functions-list.js +23 -32
- package/lib/commands/init.js +14 -1
- package/lib/commands/projects-create.js +1 -1
- package/lib/commands/use.js +4 -1
- package/lib/crashlytics/listTopIssues.js +2 -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/commandUtils.js +2 -1
- package/lib/emulator/controller.js +1 -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/gcp/storage.js +8 -4
- 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/index.js +15 -1
- package/lib/mcp/tools/core/consult_assistant.js +1 -1
- package/lib/mcp/tools/crashlytics/list_top_issues.js +7 -2
- package/lib/mcp/tools/dataconnect/emulator.js +3 -19
- package/lib/mcp/tools/dataconnect/execute_graphql.js +1 -1
- package/lib/mcp/tools/dataconnect/execute_graphql_read.js +1 -1
- package/lib/mcp/tools/dataconnect/execute_mutation.js +1 -1
- package/lib/mcp/tools/dataconnect/execute_query.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/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/lib/mcp/tools/storage/get_download_url.js +8 -2
- package/lib/track.js +4 -0
- 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
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "firebase-tools",
|
|
3
|
-
"version": "14.
|
|
3
|
+
"version": "14.7.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;
|
|
@@ -1,298 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __asyncValues = (this && this.__asyncValues) || function (o) {
|
|
3
|
-
if (!Symbol.asyncIterator) throw new TypeError("Symbol.asyncIterator is not defined.");
|
|
4
|
-
var m = o[Symbol.asyncIterator], i;
|
|
5
|
-
return m ? m.call(o) : (o = typeof __values === "function" ? __values(o) : o[Symbol.iterator](), i = {}, verb("next"), verb("throw"), verb("return"), i[Symbol.asyncIterator] = function () { return this; }, i);
|
|
6
|
-
function verb(n) { i[n] = o[n] && function (v) { return new Promise(function (resolve, reject) { v = o[n](v), settle(resolve, reject, v.done, v.value); }); }; }
|
|
7
|
-
function settle(resolve, reject, d, v) { Promise.resolve(v).then(function(v) { resolve({ value: v, done: d }); }, reject); }
|
|
8
|
-
};
|
|
9
|
-
var __await = (this && this.__await) || function (v) { return this instanceof __await ? (this.v = v, this) : new __await(v); }
|
|
10
|
-
var __asyncDelegator = (this && this.__asyncDelegator) || function (o) {
|
|
11
|
-
var i, p;
|
|
12
|
-
return i = {}, verb("next"), verb("throw", function (e) { throw e; }), verb("return"), i[Symbol.iterator] = function () { return this; }, i;
|
|
13
|
-
function verb(n, f) { i[n] = o[n] ? function (v) { return (p = !p) ? { value: __await(o[n](v)), done: n === "return" } : f ? f(v) : v; } : f; }
|
|
14
|
-
};
|
|
15
|
-
var __asyncGenerator = (this && this.__asyncGenerator) || function (thisArg, _arguments, generator) {
|
|
16
|
-
if (!Symbol.asyncIterator) throw new TypeError("Symbol.asyncIterator is not defined.");
|
|
17
|
-
var g = generator.apply(thisArg, _arguments || []), i, q = [];
|
|
18
|
-
return i = {}, verb("next"), verb("throw"), verb("return"), i[Symbol.asyncIterator] = function () { return this; }, i;
|
|
19
|
-
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); }); }; }
|
|
20
|
-
function resume(n, v) { try { step(g[n](v)); } catch (e) { settle(q[0][3], e); } }
|
|
21
|
-
function step(r) { r.value instanceof __await ? Promise.resolve(r.value.v).then(fulfill, reject) : settle(q[0][2], r); }
|
|
22
|
-
function fulfill(value) { resume("next", value); }
|
|
23
|
-
function reject(value) { resume("throw", value); }
|
|
24
|
-
function settle(f, v) { if (f(v), q.shift(), q.length) resume(q[0][0], q[0][1]); }
|
|
25
|
-
};
|
|
26
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
27
|
-
exports.decodeBase64 = exports.encodeBase64 = exports.ScramSha256AuthFlow = exports.verifyScramSha256Password = exports.createScramSha256Data = void 0;
|
|
28
|
-
const backend_error_1 = require("../../backend-error");
|
|
29
|
-
const connection_1 = require("../../connection");
|
|
30
|
-
const crypto_1 = require("../../crypto");
|
|
31
|
-
const sasl_mechanism_1 = require("./sasl-mechanism");
|
|
32
|
-
async function createScramSha256Data(password, iterations = 4096) {
|
|
33
|
-
const salt = new Uint8Array(16);
|
|
34
|
-
crypto.getRandomValues(salt);
|
|
35
|
-
const saltedPassword = await (0, crypto_1.pbkdf2)(password, salt, iterations, 32, 'SHA-256');
|
|
36
|
-
const clientKey = await (0, crypto_1.createHmacKey)(saltedPassword, 'Client Key', 'SHA-256');
|
|
37
|
-
const storedKey = await (0, crypto_1.createHashKey)(clientKey, 'SHA-256');
|
|
38
|
-
const serverKey = await (0, crypto_1.createHmacKey)(saltedPassword, 'Server Key', 'SHA-256');
|
|
39
|
-
return {
|
|
40
|
-
salt: encodeBase64(salt),
|
|
41
|
-
iterations,
|
|
42
|
-
storedKey: encodeBase64(storedKey),
|
|
43
|
-
serverKey: encodeBase64(serverKey),
|
|
44
|
-
};
|
|
45
|
-
}
|
|
46
|
-
exports.createScramSha256Data = createScramSha256Data;
|
|
47
|
-
async function verifyScramSha256Password(params) {
|
|
48
|
-
const { authMessage, clientProof, storedKey } = params;
|
|
49
|
-
const clientProofBuffer = decodeBase64(clientProof);
|
|
50
|
-
const storedKeyBuffer = decodeBase64(storedKey);
|
|
51
|
-
const clientSignature = await (0, crypto_1.createHmacKey)(storedKeyBuffer, authMessage, 'SHA-256');
|
|
52
|
-
const clientSignatureView = new Uint8Array(clientSignature);
|
|
53
|
-
const clientKey = new Uint8Array(clientProofBuffer.length);
|
|
54
|
-
for (let i = 0; i < clientProofBuffer.length; i++) {
|
|
55
|
-
clientKey[i] = clientProofBuffer[i] ^ clientSignatureView[i];
|
|
56
|
-
}
|
|
57
|
-
const computedStoredKey = await (0, crypto_1.createHashKey)(clientKey, 'SHA-256');
|
|
58
|
-
return await (0, crypto_1.timingSafeEqual)(storedKeyBuffer, computedStoredKey);
|
|
59
|
-
}
|
|
60
|
-
exports.verifyScramSha256Password = verifyScramSha256Password;
|
|
61
|
-
const ScramSha256Step = {
|
|
62
|
-
Initial: 'Initial',
|
|
63
|
-
ServerFirstMessage: 'ServerFirstMessage',
|
|
64
|
-
ServerFinalMessage: 'ServerFinalMessage',
|
|
65
|
-
Completed: 'Completed',
|
|
66
|
-
};
|
|
67
|
-
class ScramSha256AuthFlow extends sasl_mechanism_1.SaslMechanism {
|
|
68
|
-
constructor(params) {
|
|
69
|
-
var _a;
|
|
70
|
-
super({ writer: params.writer });
|
|
71
|
-
this.step = ScramSha256Step.Initial;
|
|
72
|
-
this.username = params.username;
|
|
73
|
-
this.auth = Object.assign(Object.assign({}, params.auth), { validateCredentials: (_a = params.auth.validateCredentials) !== null && _a !== void 0 ? _a : (async ({ authMessage, clientProof, scramSha256Data }) => {
|
|
74
|
-
return verifyScramSha256Password({
|
|
75
|
-
authMessage,
|
|
76
|
-
clientProof,
|
|
77
|
-
storedKey: scramSha256Data.storedKey,
|
|
78
|
-
});
|
|
79
|
-
}) });
|
|
80
|
-
this.reader = params.reader;
|
|
81
|
-
this.connectionState = params.connectionState;
|
|
82
|
-
}
|
|
83
|
-
async getScramSha256Data(params) {
|
|
84
|
-
if (!this.scramSha256Data) {
|
|
85
|
-
this.scramSha256Data = await this.auth.getScramSha256Data(params, this.connectionState);
|
|
86
|
-
}
|
|
87
|
-
return this.scramSha256Data;
|
|
88
|
-
}
|
|
89
|
-
createInitialAuthMessage() {
|
|
90
|
-
return this.createAuthenticationSASL();
|
|
91
|
-
}
|
|
92
|
-
handleClientMessage(message) {
|
|
93
|
-
return __asyncGenerator(this, arguments, function* handleClientMessage_1() {
|
|
94
|
-
switch (this.step) {
|
|
95
|
-
case ScramSha256Step.Initial:
|
|
96
|
-
return yield __await(yield __await(yield* __asyncDelegator(__asyncValues(this.handleClientFirstMessage(message)))));
|
|
97
|
-
case ScramSha256Step.ServerFirstMessage:
|
|
98
|
-
return yield __await(yield __await(yield* __asyncDelegator(__asyncValues(this.handleClientFinalMessage(message)))));
|
|
99
|
-
default:
|
|
100
|
-
throw new Error('Unexpected SCRAM-SHA-256 authentication step');
|
|
101
|
-
}
|
|
102
|
-
});
|
|
103
|
-
}
|
|
104
|
-
handleClientFirstMessage(message) {
|
|
105
|
-
return __asyncGenerator(this, arguments, function* handleClientFirstMessage_1() {
|
|
106
|
-
const length = this.reader.int32();
|
|
107
|
-
const saslMechanism = this.reader.cstring();
|
|
108
|
-
if (saslMechanism !== 'SCRAM-SHA-256') {
|
|
109
|
-
yield yield __await((0, backend_error_1.createBackendErrorMessage)({
|
|
110
|
-
severity: 'FATAL',
|
|
111
|
-
code: '28000',
|
|
112
|
-
message: 'Unsupported SASL authentication mechanism',
|
|
113
|
-
}));
|
|
114
|
-
yield yield __await(connection_1.closeSignal);
|
|
115
|
-
return yield __await(void 0);
|
|
116
|
-
}
|
|
117
|
-
const responseLength = this.reader.int32();
|
|
118
|
-
const clientFirstMessage = this.reader.string(responseLength);
|
|
119
|
-
const serverFirstMessage = yield __await(this.createServerFirstMessage(clientFirstMessage));
|
|
120
|
-
this.step = ScramSha256Step.ServerFirstMessage;
|
|
121
|
-
yield yield __await(this.createAuthenticationSASLContinue(serverFirstMessage));
|
|
122
|
-
});
|
|
123
|
-
}
|
|
124
|
-
async createServerFirstMessage(clientFirstMessage) {
|
|
125
|
-
var _a;
|
|
126
|
-
const clientFirstMessageParts = clientFirstMessage.split(',');
|
|
127
|
-
this.clientFirstMessageBare = clientFirstMessageParts.slice(2).join(',');
|
|
128
|
-
const clientNonce = ((_a = clientFirstMessageParts.find((part) => part.startsWith('r='))) === null || _a === void 0 ? void 0 : _a.substring(2)) || '';
|
|
129
|
-
const serverNoncePart = new Uint8Array(18);
|
|
130
|
-
crypto.getRandomValues(serverNoncePart);
|
|
131
|
-
this.serverNonce = clientNonce + encodeBase64(serverNoncePart);
|
|
132
|
-
const { salt, iterations } = await this.getScramSha256Data({
|
|
133
|
-
username: this.username,
|
|
134
|
-
});
|
|
135
|
-
this.serverFirstMessage = `r=${this.serverNonce},s=${salt},i=${iterations}`;
|
|
136
|
-
return this.serverFirstMessage;
|
|
137
|
-
}
|
|
138
|
-
handleClientFinalMessage(message) {
|
|
139
|
-
return __asyncGenerator(this, arguments, function* handleClientFinalMessage_1() {
|
|
140
|
-
try {
|
|
141
|
-
const serverFinalMessage = yield __await(this.createServerFinalMessage(message));
|
|
142
|
-
this.step = ScramSha256Step.Completed;
|
|
143
|
-
yield yield __await(this.createAuthenticationSASLFinal(serverFinalMessage));
|
|
144
|
-
}
|
|
145
|
-
catch (error) {
|
|
146
|
-
yield yield __await((0, backend_error_1.createBackendErrorMessage)({
|
|
147
|
-
severity: 'FATAL',
|
|
148
|
-
code: '28000',
|
|
149
|
-
message: error.message,
|
|
150
|
-
}));
|
|
151
|
-
yield yield __await(connection_1.closeSignal);
|
|
152
|
-
return yield __await(void 0);
|
|
153
|
-
}
|
|
154
|
-
});
|
|
155
|
-
}
|
|
156
|
-
get isCompleted() {
|
|
157
|
-
return this.step === ScramSha256Step.Completed;
|
|
158
|
-
}
|
|
159
|
-
async createServerFinalMessage(message) {
|
|
160
|
-
var _a, _b, _c;
|
|
161
|
-
const length = this.reader.int32();
|
|
162
|
-
const stringLength = length - 4;
|
|
163
|
-
const clientFinalMessage = this.reader.string(stringLength);
|
|
164
|
-
const clientFinalMessageParts = clientFinalMessage.split(',');
|
|
165
|
-
const channelBinding = (_a = clientFinalMessageParts
|
|
166
|
-
.find((part) => part.startsWith('c='))) === null || _a === void 0 ? void 0 : _a.substring(2);
|
|
167
|
-
const fullNonce = (_b = clientFinalMessageParts.find((part) => part.startsWith('r='))) === null || _b === void 0 ? void 0 : _b.substring(2);
|
|
168
|
-
const clientProof = (_c = clientFinalMessageParts.find((part) => part.startsWith('p='))) === null || _c === void 0 ? void 0 : _c.substring(2);
|
|
169
|
-
if (!channelBinding || !fullNonce || !clientProof) {
|
|
170
|
-
throw new Error('Invalid client final message');
|
|
171
|
-
}
|
|
172
|
-
if (fullNonce !== this.serverNonce) {
|
|
173
|
-
throw new Error('Nonce mismatch');
|
|
174
|
-
}
|
|
175
|
-
const clientFinalMessageWithoutProof = `c=${channelBinding},r=${fullNonce}`;
|
|
176
|
-
const authMessage = `${this.clientFirstMessageBare},${this.serverFirstMessage},${clientFinalMessageWithoutProof}`;
|
|
177
|
-
const data = await this.getScramSha256Data({
|
|
178
|
-
username: this.username,
|
|
179
|
-
});
|
|
180
|
-
const isValid = await this.auth.validateCredentials({
|
|
181
|
-
authMessage,
|
|
182
|
-
clientProof,
|
|
183
|
-
username: this.username,
|
|
184
|
-
scramSha256Data: data,
|
|
185
|
-
}, this.connectionState);
|
|
186
|
-
if (!isValid) {
|
|
187
|
-
throw new Error(`password authentication failed for user "${this.username}"`);
|
|
188
|
-
}
|
|
189
|
-
const serverKeyBuffer = decodeBase64(data.serverKey);
|
|
190
|
-
const serverSignature = await (0, crypto_1.createHmacKey)(serverKeyBuffer, authMessage, 'SHA-256');
|
|
191
|
-
return `v=${encodeBase64(serverSignature)}`;
|
|
192
|
-
}
|
|
193
|
-
}
|
|
194
|
-
exports.ScramSha256AuthFlow = ScramSha256AuthFlow;
|
|
195
|
-
function encodeBase64(data) {
|
|
196
|
-
const uint8 = data;
|
|
197
|
-
let result = "";
|
|
198
|
-
let i;
|
|
199
|
-
const l = uint8.length;
|
|
200
|
-
for (i = 2; i < l; i += 3) {
|
|
201
|
-
result += base64abc[(uint8[i - 2]) >> 2];
|
|
202
|
-
result += base64abc[(((uint8[i - 2]) & 0x03) << 4) |
|
|
203
|
-
((uint8[i - 1]) >> 4)];
|
|
204
|
-
result += base64abc[(((uint8[i - 1]) & 0x0f) << 2) |
|
|
205
|
-
((uint8[i]) >> 6)];
|
|
206
|
-
result += base64abc[(uint8[i]) & 0x3f];
|
|
207
|
-
}
|
|
208
|
-
if (i === l + 1) {
|
|
209
|
-
result += base64abc[(uint8[i - 2]) >> 2];
|
|
210
|
-
result += base64abc[((uint8[i - 2]) & 0x03) << 4];
|
|
211
|
-
result += "==";
|
|
212
|
-
}
|
|
213
|
-
if (i === l) {
|
|
214
|
-
result += base64abc[(uint8[i - 2]) >> 2];
|
|
215
|
-
result += base64abc[(((uint8[i - 2]) & 0x03) << 4) |
|
|
216
|
-
((uint8[i - 1]) >> 4)];
|
|
217
|
-
result += base64abc[((uint8[i - 1]) & 0x0f) << 2];
|
|
218
|
-
result += "=";
|
|
219
|
-
}
|
|
220
|
-
return result;
|
|
221
|
-
}
|
|
222
|
-
exports.encodeBase64 = encodeBase64;
|
|
223
|
-
function decodeBase64(b64) {
|
|
224
|
-
const binString = atob(b64);
|
|
225
|
-
const size = binString.length;
|
|
226
|
-
const bytes = new Uint8Array(size);
|
|
227
|
-
for (let i = 0; i < size; i++) {
|
|
228
|
-
bytes[i] = binString.charCodeAt(i);
|
|
229
|
-
}
|
|
230
|
-
return bytes;
|
|
231
|
-
}
|
|
232
|
-
exports.decodeBase64 = decodeBase64;
|
|
233
|
-
const base64abc = [
|
|
234
|
-
"A",
|
|
235
|
-
"B",
|
|
236
|
-
"C",
|
|
237
|
-
"D",
|
|
238
|
-
"E",
|
|
239
|
-
"F",
|
|
240
|
-
"G",
|
|
241
|
-
"H",
|
|
242
|
-
"I",
|
|
243
|
-
"J",
|
|
244
|
-
"K",
|
|
245
|
-
"L",
|
|
246
|
-
"M",
|
|
247
|
-
"N",
|
|
248
|
-
"O",
|
|
249
|
-
"P",
|
|
250
|
-
"Q",
|
|
251
|
-
"R",
|
|
252
|
-
"S",
|
|
253
|
-
"T",
|
|
254
|
-
"U",
|
|
255
|
-
"V",
|
|
256
|
-
"W",
|
|
257
|
-
"X",
|
|
258
|
-
"Y",
|
|
259
|
-
"Z",
|
|
260
|
-
"a",
|
|
261
|
-
"b",
|
|
262
|
-
"c",
|
|
263
|
-
"d",
|
|
264
|
-
"e",
|
|
265
|
-
"f",
|
|
266
|
-
"g",
|
|
267
|
-
"h",
|
|
268
|
-
"i",
|
|
269
|
-
"j",
|
|
270
|
-
"k",
|
|
271
|
-
"l",
|
|
272
|
-
"m",
|
|
273
|
-
"n",
|
|
274
|
-
"o",
|
|
275
|
-
"p",
|
|
276
|
-
"q",
|
|
277
|
-
"r",
|
|
278
|
-
"s",
|
|
279
|
-
"t",
|
|
280
|
-
"u",
|
|
281
|
-
"v",
|
|
282
|
-
"w",
|
|
283
|
-
"x",
|
|
284
|
-
"y",
|
|
285
|
-
"z",
|
|
286
|
-
"0",
|
|
287
|
-
"1",
|
|
288
|
-
"2",
|
|
289
|
-
"3",
|
|
290
|
-
"4",
|
|
291
|
-
"5",
|
|
292
|
-
"6",
|
|
293
|
-
"7",
|
|
294
|
-
"8",
|
|
295
|
-
"9",
|
|
296
|
-
"+",
|
|
297
|
-
"/",
|
|
298
|
-
];
|