@logto/cli 1.10.0 → 1.10.1
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/database/config.js +9 -5
- package/lib/commands/database/seed/oidc-config.js +10 -9
- package/lib/commands/database/utils.d.ts +12 -6
- package/lib/commands/database/utils.js +13 -12
- package/lib/connector/factories.d.ts +2 -1
- package/lib/connector/factories.js +5 -2
- package/lib/connector/types.d.ts +3 -2
- package/lib/connector/utils.d.ts +3 -2
- package/lib/database.d.ts +1 -1
- package/lib/package-json.d.ts +1 -0
- package/lib/package-json.js +9 -8
- package/package.json +9 -8
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import { defaultTenantId, LogtoOidcConfigKey, logtoConfigGuards, logtoConfigKeys, } from '@logto/schemas';
|
|
1
|
+
import { defaultTenantId, LogtoOidcConfigKey, logtoConfigGuards, logtoConfigKeys, SupportedSigningKeyAlgorithm, } from '@logto/schemas';
|
|
2
2
|
import { deduplicate, noop } from '@silverhand/essentials';
|
|
3
3
|
import chalk from 'chalk';
|
|
4
4
|
import { createPoolFromConfig } from '../../database.js';
|
|
5
5
|
import { getRowsByKeys, updateValueByKey } from '../../queries/logto-config.js';
|
|
6
6
|
import { consoleLog } from '../../utils.js';
|
|
7
|
-
import {
|
|
7
|
+
import { generateOidcCookieKey, generateOidcPrivateKey } from './utils.js';
|
|
8
8
|
const validKeysDisplay = chalk.green(logtoConfigKeys.join(', '));
|
|
9
9
|
const validateKeys = (keys) => {
|
|
10
10
|
const invalidKey = (Array.isArray(keys) ? keys : [keys]).find(
|
|
@@ -19,7 +19,10 @@ const validRotateKeys = Object.freeze([
|
|
|
19
19
|
LogtoOidcConfigKey.PrivateKeys,
|
|
20
20
|
LogtoOidcConfigKey.CookieKeys,
|
|
21
21
|
]);
|
|
22
|
-
const validPrivateKeyTypes = Object.freeze([
|
|
22
|
+
const validPrivateKeyTypes = Object.freeze([
|
|
23
|
+
SupportedSigningKeyAlgorithm.RSA,
|
|
24
|
+
SupportedSigningKeyAlgorithm.EC,
|
|
25
|
+
]);
|
|
23
26
|
const validateRotateKey = (key) => {
|
|
24
27
|
// Using `.includes()` will result a type error
|
|
25
28
|
// eslint-disable-next-line unicorn/prefer-includes
|
|
@@ -118,8 +121,9 @@ const rotateConfig = {
|
|
|
118
121
|
default: 'ec',
|
|
119
122
|
}),
|
|
120
123
|
handler: async ({ key, tenantId, type }) => {
|
|
124
|
+
const keyType = type.toUpperCase();
|
|
121
125
|
validateRotateKey(key);
|
|
122
|
-
validatePrivateKeyType(
|
|
126
|
+
validatePrivateKeyType(keyType);
|
|
123
127
|
const pool = await createPoolFromConfig();
|
|
124
128
|
const { rows } = await getRowsByKeys(pool, tenantId, [key]);
|
|
125
129
|
if (!rows[0]) {
|
|
@@ -131,7 +135,7 @@ const rotateConfig = {
|
|
|
131
135
|
// No need for default. It's already exhaustive
|
|
132
136
|
switch (key) {
|
|
133
137
|
case LogtoOidcConfigKey.PrivateKeys: {
|
|
134
|
-
return [await generateOidcPrivateKey(
|
|
138
|
+
return [await generateOidcPrivateKey(keyType), ...original];
|
|
135
139
|
}
|
|
136
140
|
case LogtoOidcConfigKey.CookieKeys: {
|
|
137
141
|
return [generateOidcCookieKey(), ...original];
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import { readFile } from 'node:fs/promises';
|
|
2
2
|
import { LogtoOidcConfigKey, logtoConfigGuards } from '@logto/schemas';
|
|
3
|
+
import { generateStandardId } from '@logto/shared';
|
|
3
4
|
import { getEnvAsStringArray } from '@silverhand/essentials';
|
|
4
5
|
import chalk from 'chalk';
|
|
5
6
|
import { z } from 'zod';
|
|
6
7
|
import { getRowsByKeys, updateValueByKey } from '../../../queries/logto-config.js';
|
|
7
8
|
import { consoleLog } from '../../../utils.js';
|
|
8
|
-
import { generateOidcCookieKey, generateOidcPrivateKey } from '../utils.js';
|
|
9
|
+
import { buildOidcKeyFromRawString, generateOidcCookieKey, generateOidcPrivateKey, } from '../utils.js';
|
|
9
10
|
const isBase64FormatPrivateKey = (key) => !key.includes('-');
|
|
10
11
|
export const seedOidcConfigs = async (pool, tenantId) => {
|
|
11
12
|
const tenantPrefix = `[${tenantId}]`;
|
|
@@ -67,20 +68,16 @@ export const oidcConfigReaders = {
|
|
|
67
68
|
const privateKeys = getEnvAsStringArray('OIDC_PRIVATE_KEYS');
|
|
68
69
|
if (privateKeys.length > 0) {
|
|
69
70
|
return {
|
|
70
|
-
value: privateKeys.map((key) =>
|
|
71
|
-
if (isBase64FormatPrivateKey(key)) {
|
|
72
|
-
return Buffer.from(key, 'base64').toString('utf8');
|
|
73
|
-
}
|
|
74
|
-
return key;
|
|
75
|
-
}),
|
|
71
|
+
value: privateKeys.map((key) => buildOidcKeyFromRawString(isBase64FormatPrivateKey(key) ? Buffer.from(key, 'base64').toString('utf8') : key)),
|
|
76
72
|
fromEnv: true,
|
|
77
73
|
};
|
|
78
74
|
}
|
|
79
75
|
// Read keys from files
|
|
80
76
|
const privateKeyPaths = getEnvAsStringArray('OIDC_PRIVATE_KEY_PATHS');
|
|
81
77
|
if (privateKeyPaths.length > 0) {
|
|
78
|
+
const privateKeys = await Promise.all(privateKeyPaths.map(async (path) => readFile(path, 'utf8')));
|
|
82
79
|
return {
|
|
83
|
-
value:
|
|
80
|
+
value: privateKeys.map((key) => buildOidcKeyFromRawString(key)),
|
|
84
81
|
fromEnv: true,
|
|
85
82
|
};
|
|
86
83
|
}
|
|
@@ -91,7 +88,11 @@ export const oidcConfigReaders = {
|
|
|
91
88
|
},
|
|
92
89
|
[LogtoOidcConfigKey.CookieKeys]: async () => {
|
|
93
90
|
const envKey = 'OIDC_COOKIE_KEYS';
|
|
94
|
-
const keys = getEnvAsStringArray(envKey)
|
|
91
|
+
const keys = getEnvAsStringArray(envKey).map((key) => ({
|
|
92
|
+
id: generateStandardId(),
|
|
93
|
+
value: key,
|
|
94
|
+
createdAt: Math.floor(Date.now() / 1000),
|
|
95
|
+
}));
|
|
95
96
|
return { value: keys.length > 0 ? keys : [generateOidcCookieKey()], fromEnv: keys.length > 0 };
|
|
96
97
|
},
|
|
97
98
|
};
|
|
@@ -1,6 +1,12 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
1
|
+
import { type OidcConfigKey, SupportedSigningKeyAlgorithm } from '@logto/schemas';
|
|
2
|
+
export declare const generateOidcPrivateKey: (type?: SupportedSigningKeyAlgorithm) => Promise<OidcConfigKey>;
|
|
3
|
+
export declare const generateOidcCookieKey: () => {
|
|
4
|
+
id: string;
|
|
5
|
+
value: string;
|
|
6
|
+
createdAt: number;
|
|
7
|
+
};
|
|
8
|
+
export declare const buildOidcKeyFromRawString: (raw: string) => {
|
|
9
|
+
id: string;
|
|
10
|
+
value: string;
|
|
11
|
+
createdAt: number;
|
|
12
|
+
};
|
|
@@ -1,13 +1,9 @@
|
|
|
1
1
|
import { generateKeyPair } from 'node:crypto';
|
|
2
2
|
import { promisify } from 'node:util';
|
|
3
|
-
import {
|
|
4
|
-
|
|
5
|
-
(
|
|
6
|
-
|
|
7
|
-
PrivateKeyType["EC"] = "ec";
|
|
8
|
-
})(PrivateKeyType || (PrivateKeyType = {}));
|
|
9
|
-
export const generateOidcPrivateKey = async (type = PrivateKeyType.EC) => {
|
|
10
|
-
if (type === PrivateKeyType.RSA) {
|
|
3
|
+
import { SupportedSigningKeyAlgorithm } from '@logto/schemas';
|
|
4
|
+
import { generateStandardId, generateStandardSecret } from '@logto/shared';
|
|
5
|
+
export const generateOidcPrivateKey = async (type = SupportedSigningKeyAlgorithm.EC) => {
|
|
6
|
+
if (type === SupportedSigningKeyAlgorithm.RSA) {
|
|
11
7
|
const { privateKey } = await promisify(generateKeyPair)('rsa', {
|
|
12
8
|
modulusLength: 4096,
|
|
13
9
|
publicKeyEncoding: {
|
|
@@ -19,10 +15,10 @@ export const generateOidcPrivateKey = async (type = PrivateKeyType.EC) => {
|
|
|
19
15
|
format: 'pem',
|
|
20
16
|
},
|
|
21
17
|
});
|
|
22
|
-
return privateKey;
|
|
18
|
+
return buildOidcKeyFromRawString(privateKey);
|
|
23
19
|
}
|
|
24
20
|
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
|
25
|
-
if (type ===
|
|
21
|
+
if (type === SupportedSigningKeyAlgorithm.EC) {
|
|
26
22
|
const { privateKey } = await promisify(generateKeyPair)('ec', {
|
|
27
23
|
// https://security.stackexchange.com/questions/78621/which-elliptic-curve-should-i-use
|
|
28
24
|
namedCurve: 'secp384r1',
|
|
@@ -35,8 +31,13 @@ export const generateOidcPrivateKey = async (type = PrivateKeyType.EC) => {
|
|
|
35
31
|
format: 'pem',
|
|
36
32
|
},
|
|
37
33
|
});
|
|
38
|
-
return privateKey;
|
|
34
|
+
return buildOidcKeyFromRawString(privateKey);
|
|
39
35
|
}
|
|
40
36
|
throw new Error(`Unsupported private key ${String(type)}`);
|
|
41
37
|
};
|
|
42
|
-
export const generateOidcCookieKey = () => generateStandardSecret();
|
|
38
|
+
export const generateOidcCookieKey = () => buildOidcKeyFromRawString(generateStandardSecret());
|
|
39
|
+
export const buildOidcKeyFromRawString = (raw) => ({
|
|
40
|
+
id: generateStandardId(),
|
|
41
|
+
value: raw,
|
|
42
|
+
createdAt: Math.floor(Date.now() / 1000),
|
|
43
|
+
});
|
|
@@ -1,2 +1,3 @@
|
|
|
1
|
+
import type { BaseRoutes, Router } from '@withtyped/server';
|
|
1
2
|
import type { ConnectorFactory, ConnectorPackage } from './types.js';
|
|
2
|
-
export declare const loadConnectorFactories: (connectorPackages: ConnectorPackage[], ignoreVersionMismatch: boolean) => Promise<ConnectorFactory[]>;
|
|
3
|
+
export declare const loadConnectorFactories: (connectorPackages: ConnectorPackage[], ignoreVersionMismatch: boolean) => Promise<ConnectorFactory<Router<any, BaseRoutes, string>>[]>;
|
|
@@ -3,7 +3,7 @@ import { consoleLog } from '../utils.js';
|
|
|
3
3
|
import { notImplemented } from './consts.js';
|
|
4
4
|
import { loadConnector } from './loader.js';
|
|
5
5
|
import { parseMetadata, validateConnectorModule } from './utils.js';
|
|
6
|
-
// eslint-disable-next-line @silverhand/fp/no-let
|
|
6
|
+
// eslint-disable-next-line @silverhand/fp/no-let, @typescript-eslint/no-explicit-any
|
|
7
7
|
let cachedConnectorFactories;
|
|
8
8
|
export const loadConnectorFactories = async (connectorPackages, ignoreVersionMismatch) => {
|
|
9
9
|
if (cachedConnectorFactories) {
|
|
@@ -17,6 +17,7 @@ export const loadConnectorFactories = async (connectorPackages, ignoreVersionMis
|
|
|
17
17
|
return {
|
|
18
18
|
metadata: await parseMetadata(rawConnector.metadata, packagePath),
|
|
19
19
|
type: rawConnector.type,
|
|
20
|
+
configGuard: rawConnector.configGuard,
|
|
20
21
|
createConnector,
|
|
21
22
|
path: packagePath,
|
|
22
23
|
};
|
|
@@ -30,6 +31,8 @@ export const loadConnectorFactories = async (connectorPackages, ignoreVersionMis
|
|
|
30
31
|
}
|
|
31
32
|
}));
|
|
32
33
|
// eslint-disable-next-line @silverhand/fp/no-mutation
|
|
33
|
-
cachedConnectorFactories = connectorFactories.filter(
|
|
34
|
+
cachedConnectorFactories = connectorFactories.filter(
|
|
35
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
36
|
+
(connectorFactory) => connectorFactory !== undefined);
|
|
34
37
|
return cachedConnectorFactories;
|
|
35
38
|
};
|
package/lib/connector/types.d.ts
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import type { AllConnector, CreateConnector } from '@logto/connector-kit';
|
|
2
|
+
import type { BaseRoutes, Router } from '@withtyped/server';
|
|
2
3
|
/**
|
|
3
4
|
* Dynamic loaded connector type.
|
|
4
5
|
*/
|
|
5
|
-
export type ConnectorFactory<T extends AllConnector = AllConnector> = Pick<
|
|
6
|
-
createConnector: CreateConnector<T>;
|
|
6
|
+
export type ConnectorFactory<T extends Router<any, BaseRoutes, string>, U extends AllConnector = AllConnector> = Pick<U, 'type' | 'metadata' | 'configGuard'> & {
|
|
7
|
+
createConnector: CreateConnector<U, T>;
|
|
7
8
|
path: string;
|
|
8
9
|
};
|
|
9
10
|
export type ConnectorPackage = {
|
package/lib/connector/utils.d.ts
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import type { AllConnector, BaseConnector, ConnectorMetadata, GetConnectorConfig, GetCloudServiceClient } from '@logto/connector-kit';
|
|
2
2
|
import { ConnectorType } from '@logto/connector-kit';
|
|
3
|
+
import type { BaseRoutes, Router } from '@withtyped/server';
|
|
3
4
|
import type { ConnectorFactory } from './types.js';
|
|
4
5
|
export declare function validateConnectorModule(connector: Partial<BaseConnector<ConnectorType>>): asserts connector is BaseConnector<ConnectorType>;
|
|
5
6
|
export declare const readUrl: (url: string, baseUrl: string, type: 'text' | 'image') => Promise<string>;
|
|
6
7
|
export declare const parseMetadata: (metadata: AllConnector['metadata'], packagePath: string) => Promise<AllConnector['metadata']>;
|
|
7
|
-
export declare const buildRawConnector: <T extends AllConnector = AllConnector>(connectorFactory: ConnectorFactory<T>, getConnectorConfig?: GetConnectorConfig, getCloudServiceClient?: GetCloudServiceClient) => Promise<{
|
|
8
|
-
rawConnector:
|
|
8
|
+
export declare const buildRawConnector: <T extends Router<any, BaseRoutes, string>, U extends AllConnector = AllConnector>(connectorFactory: ConnectorFactory<T, U>, getConnectorConfig?: GetConnectorConfig, getCloudServiceClient?: GetCloudServiceClient<T> | undefined) => Promise<{
|
|
9
|
+
rawConnector: U;
|
|
9
10
|
rawMetadata: ConnectorMetadata;
|
|
10
11
|
}>;
|
|
11
12
|
export declare const isKeyInObject: <Key extends string>(object: unknown, key: Key) => object is Record<string, unknown> & Record<Key, unknown>;
|
package/lib/database.d.ts
CHANGED
|
@@ -9,4 +9,4 @@ export declare const createPoolFromConfig: () => Promise<import("slonik").Databa
|
|
|
9
9
|
* @returns A new database pool with the database URL in config.
|
|
10
10
|
*/
|
|
11
11
|
export declare const createPoolAndDatabaseIfNeeded: () => Promise<import("slonik").DatabasePool>;
|
|
12
|
-
export declare const insertInto: <T extends SchemaLike
|
|
12
|
+
export declare const insertInto: <T extends SchemaLike<string>>(object: T, table: string) => import("slonik").TaggedTemplateLiteralInvocation<import("slonik").QueryResultRow>;
|
package/lib/package-json.d.ts
CHANGED
package/lib/package-json.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
export const packageJson = {
|
|
2
2
|
"name": "@logto/cli",
|
|
3
|
-
"version": "1.10.
|
|
3
|
+
"version": "1.10.1",
|
|
4
4
|
"description": "Logto CLI.",
|
|
5
5
|
"author": "Silverhand Inc. <contact@silverhand.io>",
|
|
6
6
|
"homepage": "https://github.com/logto-io/logto#readme",
|
|
@@ -43,12 +43,12 @@ export const packageJson = {
|
|
|
43
43
|
"url": "https://github.com/logto-io/logto/issues"
|
|
44
44
|
},
|
|
45
45
|
"dependencies": {
|
|
46
|
-
"@logto/connector-kit": "workspace:^
|
|
46
|
+
"@logto/connector-kit": "workspace:^2.0.0",
|
|
47
47
|
"@logto/core-kit": "workspace:^2.2.0",
|
|
48
48
|
"@logto/language-kit": "workspace:^1.0.0",
|
|
49
|
-
"@logto/phrases": "workspace:^1.
|
|
49
|
+
"@logto/phrases": "workspace:^1.6.0",
|
|
50
50
|
"@logto/phrases-experience": "workspace:^1.3.1",
|
|
51
|
-
"@logto/schemas": "workspace:1.10.
|
|
51
|
+
"@logto/schemas": "workspace:1.10.1",
|
|
52
52
|
"@logto/shared": "workspace:^3.0.0",
|
|
53
53
|
"@silverhand/essentials": "^2.8.4",
|
|
54
54
|
"chalk": "^5.0.0",
|
|
@@ -57,7 +57,7 @@ export const packageJson = {
|
|
|
57
57
|
"got": "^13.0.0",
|
|
58
58
|
"hpagent": "^1.2.0",
|
|
59
59
|
"inquirer": "^9.0.0",
|
|
60
|
-
"nanoid": "^
|
|
60
|
+
"nanoid": "^5.0.1",
|
|
61
61
|
"ora": "^6.1.2",
|
|
62
62
|
"p-limit": "^4.0.0",
|
|
63
63
|
"p-queue": "^7.3.4",
|
|
@@ -71,11 +71,12 @@ export const packageJson = {
|
|
|
71
71
|
"tar": "^6.1.11",
|
|
72
72
|
"typescript": "^5.0.0",
|
|
73
73
|
"yargs": "^17.6.0",
|
|
74
|
-
"zod": "^3.
|
|
74
|
+
"zod": "^3.22.3"
|
|
75
75
|
},
|
|
76
76
|
"devDependencies": {
|
|
77
77
|
"@silverhand/eslint-config": "4.0.1",
|
|
78
78
|
"@silverhand/ts-config": "4.0.0",
|
|
79
|
+
"@withtyped/server": "^0.12.9",
|
|
79
80
|
"@types/inquirer": "^9.0.0",
|
|
80
81
|
"@types/jest": "^29.4.0",
|
|
81
82
|
"@types/node": "^18.11.18",
|
|
@@ -85,9 +86,9 @@ export const packageJson = {
|
|
|
85
86
|
"@types/yargs": "^17.0.13",
|
|
86
87
|
"eslint": "^8.44.0",
|
|
87
88
|
"jest": "^29.5.0",
|
|
88
|
-
"lint-staged": "^
|
|
89
|
+
"lint-staged": "^15.0.0",
|
|
89
90
|
"prettier": "^3.0.0",
|
|
90
|
-
"sinon": "^
|
|
91
|
+
"sinon": "^17.0.0"
|
|
91
92
|
},
|
|
92
93
|
"eslintConfig": {
|
|
93
94
|
"extends": "@silverhand",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@logto/cli",
|
|
3
|
-
"version": "1.10.
|
|
3
|
+
"version": "1.10.1",
|
|
4
4
|
"description": "Logto CLI.",
|
|
5
5
|
"author": "Silverhand Inc. <contact@silverhand.io>",
|
|
6
6
|
"homepage": "https://github.com/logto-io/logto#readme",
|
|
@@ -28,12 +28,12 @@
|
|
|
28
28
|
"url": "https://github.com/logto-io/logto/issues"
|
|
29
29
|
},
|
|
30
30
|
"dependencies": {
|
|
31
|
-
"@logto/connector-kit": "^
|
|
31
|
+
"@logto/connector-kit": "^2.0.0",
|
|
32
32
|
"@logto/core-kit": "^2.2.0",
|
|
33
33
|
"@logto/language-kit": "^1.0.0",
|
|
34
|
-
"@logto/phrases": "^1.
|
|
34
|
+
"@logto/phrases": "^1.6.0",
|
|
35
35
|
"@logto/phrases-experience": "^1.3.1",
|
|
36
|
-
"@logto/schemas": "1.10.
|
|
36
|
+
"@logto/schemas": "1.10.1",
|
|
37
37
|
"@logto/shared": "^3.0.0",
|
|
38
38
|
"@silverhand/essentials": "^2.8.4",
|
|
39
39
|
"chalk": "^5.0.0",
|
|
@@ -42,7 +42,7 @@
|
|
|
42
42
|
"got": "^13.0.0",
|
|
43
43
|
"hpagent": "^1.2.0",
|
|
44
44
|
"inquirer": "^9.0.0",
|
|
45
|
-
"nanoid": "^
|
|
45
|
+
"nanoid": "^5.0.1",
|
|
46
46
|
"ora": "^6.1.2",
|
|
47
47
|
"p-limit": "^4.0.0",
|
|
48
48
|
"p-queue": "^7.3.4",
|
|
@@ -56,11 +56,12 @@
|
|
|
56
56
|
"tar": "^6.1.11",
|
|
57
57
|
"typescript": "^5.0.0",
|
|
58
58
|
"yargs": "^17.6.0",
|
|
59
|
-
"zod": "^3.
|
|
59
|
+
"zod": "^3.22.3"
|
|
60
60
|
},
|
|
61
61
|
"devDependencies": {
|
|
62
62
|
"@silverhand/eslint-config": "4.0.1",
|
|
63
63
|
"@silverhand/ts-config": "4.0.0",
|
|
64
|
+
"@withtyped/server": "^0.12.9",
|
|
64
65
|
"@types/inquirer": "^9.0.0",
|
|
65
66
|
"@types/jest": "^29.4.0",
|
|
66
67
|
"@types/node": "^18.11.18",
|
|
@@ -70,9 +71,9 @@
|
|
|
70
71
|
"@types/yargs": "^17.0.13",
|
|
71
72
|
"eslint": "^8.44.0",
|
|
72
73
|
"jest": "^29.5.0",
|
|
73
|
-
"lint-staged": "^
|
|
74
|
+
"lint-staged": "^15.0.0",
|
|
74
75
|
"prettier": "^3.0.0",
|
|
75
|
-
"sinon": "^
|
|
76
|
+
"sinon": "^17.0.0"
|
|
76
77
|
},
|
|
77
78
|
"eslintConfig": {
|
|
78
79
|
"extends": "@silverhand",
|