@things-factory/integration-base 10.1.111 → 10.1.116
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/README.md +3 -3
- package/dist-server/engine/connector/operato-connector.js +1 -1
- package/dist-server/engine/connector/operato-connector.js.map +1 -1
- package/dist-server/engine/scenario-engine.d.ts +20 -0
- package/dist-server/engine/scenario-engine.js +43 -6
- package/dist-server/engine/scenario-engine.js.map +1 -1
- package/dist-server/routers/scenario-schedule-callback-router.js +6 -6
- package/dist-server/routers/scenario-schedule-callback-router.js.map +1 -1
- package/dist-server/routers/scenario-schedule-run.d.ts +29 -0
- package/dist-server/routers/scenario-schedule-run.js +65 -0
- package/dist-server/routers/scenario-schedule-run.js.map +1 -0
- package/dist-server/service/connection/connection-mutation.js +47 -3
- package/dist-server/service/connection/connection-mutation.js.map +1 -1
- package/dist-server/service/connection/connection-query.d.ts +9 -0
- package/dist-server/service/connection/connection-query.js +34 -0
- package/dist-server/service/connection/connection-query.js.map +1 -1
- package/dist-server/service/connection/connection-secrets.d.ts +104 -0
- package/dist-server/service/connection/connection-secrets.js +188 -0
- package/dist-server/service/connection/connection-secrets.js.map +1 -0
- package/dist-server/service/connection/connection.js.map +1 -1
- package/dist-server/service/domain-attribute/domain-attribute-query.d.ts +4 -0
- package/dist-server/service/domain-attribute/domain-attribute-query.js +9 -1
- package/dist-server/service/domain-attribute/domain-attribute-query.js.map +1 -1
- package/dist-server/service/domain-attribute/domain-attribute-type.d.ts +1 -0
- package/dist-server/service/domain-attribute/domain-attribute-type.js +8 -1
- package/dist-server/service/domain-attribute/domain-attribute-type.js.map +1 -1
- package/dist-server/service/domain-attribute/secret-keys.d.ts +13 -0
- package/dist-server/service/domain-attribute/secret-keys.js +85 -0
- package/dist-server/service/domain-attribute/secret-keys.js.map +1 -0
- package/dist-server/service/scenario-instance/scenario-instance-type.d.ts +15 -0
- package/dist-server/service/scenario-instance/scenario-instance-type.js +4 -2
- package/dist-server/service/scenario-instance/scenario-instance-type.js.map +1 -1
- package/dist-server/service/secret-hint.d.ts +20 -0
- package/dist-server/service/secret-hint.js +41 -0
- package/dist-server/service/secret-hint.js.map +1 -0
- package/dist-server/tsconfig.tsbuildinfo +1 -1
- package/package.json +9 -8
- package/translations/en.json +2 -0
- package/translations/ja.json +2 -0
- package/translations/ko.json +2 -0
- package/translations/ms.json +2 -0
- package/translations/zh.json +2 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"connection-mutation.js","sourceRoot":"","sources":["../../../server/service/connection/connection-mutation.ts"],"names":[],"mappings":"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","sourcesContent":["import { Arg, Ctx, Directive, Mutation, Resolver } from 'type-graphql'\nimport { In } from 'typeorm'\n\nimport { getRepository } from '@things-factory/shell'\n\nimport { ConnectionManager } from '../../engine/connection-manager'\nimport { Connection, ConnectionStatus } from './connection'\nimport { ConnectionPatch, NewConnection } from './connection-type'\nimport { getDomainIdsWithAncestors } from '../../utils/domain-inheritance'\n\n@Resolver(Connection)\nexport class ConnectionMutation {\n @Directive('@transaction')\n @Directive(\n '@privilege(category: \"connection\", privilege: \"mutation\", domainOwnerGranted: true, superUserGranted: true)'\n )\n @Mutation(returns => Connection, { description: 'Creates a new connection.' })\n async createConnection(\n @Arg('connection') connection: NewConnection,\n @Ctx() context: ResolverContext\n ): Promise<Connection> {\n const { domain, user, tx } = context.state\n\n return await tx.getRepository(Connection).save({\n ...connection,\n domain,\n creator: user,\n updater: user\n })\n }\n\n @Directive('@transaction')\n @Directive(\n '@privilege(category: \"connection\", privilege: \"mutation\", domainOwnerGranted: true, superUserGranted: true)'\n )\n @Mutation(returns => Connection, { description: 'Updates an existing connection.' })\n async updateConnection(\n @Arg('name') name: string,\n @Arg('patch') patch: ConnectionPatch,\n @Ctx() context: ResolverContext\n ): Promise<Connection> {\n const { domain, user, tx } = context.state\n\n const repository = tx.getRepository(Connection)\n const connection = await repository.findOne({\n where: { domain: { id: domain.id }, name }\n })\n\n return await repository.save({\n ...connection,\n ...patch,\n updater: user\n })\n }\n\n @Directive('@transaction')\n @Directive(\n '@privilege(category: \"connection\", privilege: \"mutation\", domainOwnerGranted: true, superUserGranted: true)'\n )\n @Mutation(returns => [Connection], { description: 'Updates multiple connections at once.' })\n async updateMultipleConnection(\n @Arg('patches', type => [ConnectionPatch]) patches: ConnectionPatch[],\n @Ctx() context: ResolverContext\n ): Promise<Connection[]> {\n const { domain, user, tx } = context.state\n\n let results = []\n const _createRecords = patches.filter((patch: any) => patch.cuFlag.toUpperCase() === '+')\n const _updateRecords = patches.filter((patch: any) => patch.cuFlag.toUpperCase() === 'M')\n const connectionRepo = tx.getRepository(Connection)\n\n if (_createRecords.length > 0) {\n for (let i = 0; i < _createRecords.length; i++) {\n const newRecord = _createRecords[i]\n\n const result = await connectionRepo.save({\n ...newRecord,\n domain,\n creator: user,\n updater: user\n })\n\n results.push({ ...result, cuFlag: '+' })\n }\n }\n\n if (_updateRecords.length > 0) {\n for (let i = 0; i < _updateRecords.length; i++) {\n const newRecord = _updateRecords[i]\n const connection = await connectionRepo.findOneBy({ id: newRecord.id })\n\n const result = await connectionRepo.save({\n ...connection,\n ...newRecord,\n updater: user\n })\n\n results.push({ ...result, cuFlag: 'M' })\n }\n }\n\n return results\n }\n\n @Directive('@transaction')\n @Directive(\n '@privilege(category: \"connection\", privilege: \"mutation\", domainOwnerGranted: true, superUserGranted: true)'\n )\n @Mutation(returns => Boolean, { description: 'Deletes a single connection by its name.' })\n async deleteConnection(@Arg('name') name: string, @Ctx() context: ResolverContext): Promise<boolean> {\n const { domain, tx } = context.state\n\n await tx.getRepository(Connection).delete({ domain: { id: domain.id }, name })\n return true\n }\n\n @Directive('@transaction')\n @Directive(\n '@privilege(category: \"connection\", privilege: \"mutation\", domainOwnerGranted: true, superUserGranted: true)'\n )\n @Mutation(returns => Boolean, { description: 'Deletes multiple connections by their names.' })\n async deleteConnections(\n @Arg('names', type => [String]) names: string[],\n @Ctx() context: ResolverContext\n ): Promise<boolean> {\n const { domain, tx } = context.state\n\n await tx.getRepository(Connection).delete({\n domain: { id: domain.id },\n name: In(names)\n })\n\n return true\n }\n\n @Directive('@transaction')\n @Directive(\n '@privilege(category: \"connection\", privilege: \"mutation\", domainOwnerGranted: true, superUserGranted: true)'\n )\n @Mutation(returns => Connection, { description: 'Establishes a live connection to a configured endpoint.' })\n async connectConnection(@Arg('name') name: string, @Ctx() context: ResolverContext): Promise<Connection> {\n const { domain } = context.state\n var repository = getRepository(Connection)\n\n // ancestor 도메인을 closest-first 로 순회하여 first hit 사용\n const domainIds = await getDomainIdsWithAncestors(domain)\n var connection: Connection | null = null\n for (const did of domainIds) {\n connection = await repository.findOne({\n where: { domain: { id: did }, name },\n relations: ['domain', 'edge']\n })\n if (connection) break\n }\n\n if (!connection) {\n throw new Error(`Connection with name '${name}' not found`)\n }\n\n /* 상속 및 on-demand 연결에서 connection.domain 과 다를 수 있음 */\n if (connection.domain.id !== domain.id) {\n connection.domain = domain\n await connection.connect()\n /* on-demand 연결인 경우에 connection을 저장하지 말아야 한다. */\n } else {\n await connection.connect()\n await repository.save(connection)\n }\n\n return {\n ...connection,\n state: ConnectionManager.getConnectionInstance(connection)\n ? ConnectionStatus.CONNECTED\n : ConnectionStatus.DISCONNECTED\n } as Connection\n }\n\n @Directive('@transaction')\n @Directive(\n '@privilege(category: \"connection\", privilege: \"mutation\", domainOwnerGranted: true, superUserGranted: true)'\n )\n @Mutation(returns => Connection, { description: 'Terminates a live connection.' })\n async disconnectConnection(@Arg('name') name: string, @Ctx() context: ResolverContext) {\n const { domain } = context.state\n\n var repository = getRepository(Connection)\n\n // ancestor 도메인을 closest-first 로 순회하여 first hit 사용\n const domainIds = await getDomainIdsWithAncestors(domain)\n var connection: Connection | null = null\n for (const did of domainIds) {\n connection = await repository.findOne({\n where: { domain: { id: did }, name },\n relations: ['domain', 'edge']\n })\n if (connection) break\n }\n\n if (!connection) {\n throw new Error(`Connection with name '${name}' not found`)\n }\n\n /* 상속 및 on-demand 연결에서 connection.domain 과 다를 수 있음 */\n\n /* 상속 및 on-demand 연결에서 connection.domain 과 다를 수 있음 */\n if (connection.domain.id !== domain.id) {\n connection.domain = domain\n await connection.disconnect()\n\n /* on-demand 연결인 경우에 connection을 저장하지 말아야 한다. */\n } else {\n await connection.disconnect()\n await repository.save(connection)\n }\n\n return {\n ...connection,\n state: ConnectionManager.getConnectionInstance(connection)\n ? ConnectionStatus.CONNECTED\n : ConnectionStatus.DISCONNECTED\n }\n }\n\n @Directive('@transaction')\n @Directive(\n '@privilege(category: \"connection\", privilege: \"mutation\", domainOwnerGranted: true, superUserGranted: true)'\n )\n @Mutation(returns => Boolean, {\n description: 'Imports multiple connections. Can overwrite existing connections if IDs or names match.'\n })\n async importConnections(\n @Arg('connections', type => [ConnectionPatch]) connections: Connection[],\n @Ctx() context: ResolverContext\n ): Promise<boolean> {\n const { tx, domain, user } = context.state\n\n const repository = tx.getRepository(Connection)\n\n await Promise.all(\n connections.map(async (connection: Connection) => {\n const { id, name } = connection\n\n if (id) {\n const sameId = await repository.findOneBy({ id })\n\n if (sameId) {\n if (sameId.domainId != domain.id) {\n throw `Connection with id '${id}:${name}' is already taken by another domain`\n }\n\n const sameName = await repository.findOneBy({ domain: { id: domain.id }, name })\n if (sameName && sameName.id != id) {\n throw `Connection with name '${name}' is already taken by another connection`\n }\n\n await repository.save({\n ...sameId,\n ...connection,\n domain,\n updater: user\n })\n\n return\n }\n }\n\n await repository.save({\n ...connection,\n domain,\n updater: user,\n creator: user\n })\n })\n )\n\n return true\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"connection-mutation.js","sourceRoot":"","sources":["../../../server/service/connection/connection-mutation.ts"],"names":[],"mappings":"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","sourcesContent":["import { Arg, Ctx, Directive, Mutation, Resolver, UseMiddleware } from 'type-graphql'\nimport { In } from 'typeorm'\n\nimport { getRepository, Refusal, SpeakRefusals } from '@things-factory/shell'\n\nimport { ConnectionManager } from '../../engine/connection-manager'\nimport { Connection, ConnectionStatus } from './connection'\nimport { ConnectionPatch, NewConnection } from './connection-type'\nimport { getDomainIdsWithAncestors } from '../../utils/domain-inheritance'\nimport { keepStoredSecrets, refuseSecretParams, withoutSecretsOf } from './connection-secrets'\n\n/**\n * The params a write stores (ADR-0112): a secret the caller sends is refused, a secret the caller\n * leaves out is kept from the stored row.\n *\n * A write that changes the connector type keeps none of the old type's secrets. They were secrets\n * under the old type's spec; the new type may not declare them, and then reading would show them.\n * When the old type is not registered here nobody can say which were secret, so none of its params\n * are carried over.\n */\nfunction paramsToStore(written: Partial<Connection>, stored?: Connection) {\n const type = written.type ?? stored?.type\n const name = written.name ?? stored?.name\n const typeChanged = Boolean(stored && written.type && written.type !== stored.type)\n\n if (written.params === undefined) {\n return typeChanged ? { params: withoutSecretsOf(stored.type, stored.params) } : {}\n }\n\n refuseSecretParams(type, name, written.params)\n return { params: typeChanged ? written.params : keepStoredSecrets(type, written.params, stored?.params) }\n}\n\n/**\n * A write names an existing row only through this: the row of that id or name **in the request's\n * domain**. `save` writes by primary key, so an id from another domain left in the object would\n * overwrite that domain's row - the lookup alone does not stop it.\n */\nfunction notInThisDomain(connection: string) {\n return new Refusal(\n 'connection-not-in-domain',\n { connection },\n `There is no connection \"${connection}\" in this domain.`\n )\n}\n\n@Resolver(Connection)\n@UseMiddleware(SpeakRefusals)\nexport class ConnectionMutation {\n @Directive('@transaction')\n @Directive(\n '@privilege(category: \"connection\", privilege: \"mutation\", domainOwnerGranted: true, superUserGranted: true)'\n )\n @Mutation(returns => Connection, { description: 'Creates a new connection.' })\n async createConnection(\n @Arg('connection') connection: NewConnection,\n @Ctx() context: ResolverContext\n ): Promise<Connection> {\n const { domain, user, tx } = context.state\n\n return await tx.getRepository(Connection).save({\n ...connection,\n ...paramsToStore(connection),\n domain,\n creator: user,\n updater: user\n })\n }\n\n @Directive('@transaction')\n @Directive(\n '@privilege(category: \"connection\", privilege: \"mutation\", domainOwnerGranted: true, superUserGranted: true)'\n )\n @Mutation(returns => Connection, { description: 'Updates an existing connection.' })\n async updateConnection(\n @Arg('name') name: string,\n @Arg('patch') patch: ConnectionPatch,\n @Ctx() context: ResolverContext\n ): Promise<Connection> {\n const { domain, user, tx } = context.state\n\n const repository = tx.getRepository(Connection)\n const connection = await repository.findOne({\n where: { domain: { id: domain.id }, name }\n })\n\n if (!connection) {\n throw notInThisDomain(name)\n }\n\n return await repository.save({\n ...connection,\n ...patch,\n ...paramsToStore(patch, connection),\n id: connection.id,\n updater: user\n })\n }\n\n @Directive('@transaction')\n @Directive(\n '@privilege(category: \"connection\", privilege: \"mutation\", domainOwnerGranted: true, superUserGranted: true)'\n )\n @Mutation(returns => [Connection], { description: 'Updates multiple connections at once.' })\n async updateMultipleConnection(\n @Arg('patches', type => [ConnectionPatch]) patches: ConnectionPatch[],\n @Ctx() context: ResolverContext\n ): Promise<Connection[]> {\n const { domain, user, tx } = context.state\n\n let results = []\n const _createRecords = patches.filter((patch: any) => patch.cuFlag.toUpperCase() === '+')\n const _updateRecords = patches.filter((patch: any) => patch.cuFlag.toUpperCase() === 'M')\n const connectionRepo = tx.getRepository(Connection)\n\n if (_createRecords.length > 0) {\n for (let i = 0; i < _createRecords.length; i++) {\n /* A new row: an id it carries would make `save` overwrite the row of that id, wherever it is. */\n const { id, ...newRecord } = _createRecords[i]\n\n const result = await connectionRepo.save({\n ...newRecord,\n ...paramsToStore(newRecord),\n domain,\n creator: user,\n updater: user\n })\n\n results.push({ ...result, cuFlag: '+' })\n }\n }\n\n if (_updateRecords.length > 0) {\n for (let i = 0; i < _updateRecords.length; i++) {\n const newRecord = _updateRecords[i]\n const connection = await connectionRepo.findOneBy({ id: newRecord.id, domain: { id: domain.id } })\n\n if (!connection) {\n throw notInThisDomain(newRecord.name || newRecord.id)\n }\n\n const result = await connectionRepo.save({\n ...connection,\n ...newRecord,\n ...paramsToStore(newRecord, connection),\n id: connection.id,\n updater: user\n })\n\n results.push({ ...result, cuFlag: 'M' })\n }\n }\n\n return results\n }\n\n @Directive('@transaction')\n @Directive(\n '@privilege(category: \"connection\", privilege: \"mutation\", domainOwnerGranted: true, superUserGranted: true)'\n )\n @Mutation(returns => Boolean, { description: 'Deletes a single connection by its name.' })\n async deleteConnection(@Arg('name') name: string, @Ctx() context: ResolverContext): Promise<boolean> {\n const { domain, tx } = context.state\n\n await tx.getRepository(Connection).delete({ domain: { id: domain.id }, name })\n return true\n }\n\n @Directive('@transaction')\n @Directive(\n '@privilege(category: \"connection\", privilege: \"mutation\", domainOwnerGranted: true, superUserGranted: true)'\n )\n @Mutation(returns => Boolean, { description: 'Deletes multiple connections by their names.' })\n async deleteConnections(\n @Arg('names', type => [String]) names: string[],\n @Ctx() context: ResolverContext\n ): Promise<boolean> {\n const { domain, tx } = context.state\n\n await tx.getRepository(Connection).delete({\n domain: { id: domain.id },\n name: In(names)\n })\n\n return true\n }\n\n @Directive('@transaction')\n @Directive(\n '@privilege(category: \"connection\", privilege: \"mutation\", domainOwnerGranted: true, superUserGranted: true)'\n )\n @Mutation(returns => Connection, { description: 'Establishes a live connection to a configured endpoint.' })\n async connectConnection(@Arg('name') name: string, @Ctx() context: ResolverContext): Promise<Connection> {\n const { domain } = context.state\n var repository = getRepository(Connection)\n\n // ancestor 도메인을 closest-first 로 순회하여 first hit 사용\n const domainIds = await getDomainIdsWithAncestors(domain)\n var connection: Connection | null = null\n for (const did of domainIds) {\n connection = await repository.findOne({\n where: { domain: { id: did }, name },\n relations: ['domain', 'edge']\n })\n if (connection) break\n }\n\n if (!connection) {\n throw new Error(`Connection with name '${name}' not found`)\n }\n\n /* 상속 및 on-demand 연결에서 connection.domain 과 다를 수 있음 */\n if (connection.domain.id !== domain.id) {\n connection.domain = domain\n await connection.connect()\n /* on-demand 연결인 경우에 connection을 저장하지 말아야 한다. */\n } else {\n await connection.connect()\n await repository.save(connection)\n }\n\n return {\n ...connection,\n state: ConnectionManager.getConnectionInstance(connection)\n ? ConnectionStatus.CONNECTED\n : ConnectionStatus.DISCONNECTED\n } as Connection\n }\n\n @Directive('@transaction')\n @Directive(\n '@privilege(category: \"connection\", privilege: \"mutation\", domainOwnerGranted: true, superUserGranted: true)'\n )\n @Mutation(returns => Connection, { description: 'Terminates a live connection.' })\n async disconnectConnection(@Arg('name') name: string, @Ctx() context: ResolverContext) {\n const { domain } = context.state\n\n var repository = getRepository(Connection)\n\n // ancestor 도메인을 closest-first 로 순회하여 first hit 사용\n const domainIds = await getDomainIdsWithAncestors(domain)\n var connection: Connection | null = null\n for (const did of domainIds) {\n connection = await repository.findOne({\n where: { domain: { id: did }, name },\n relations: ['domain', 'edge']\n })\n if (connection) break\n }\n\n if (!connection) {\n throw new Error(`Connection with name '${name}' not found`)\n }\n\n /* 상속 및 on-demand 연결에서 connection.domain 과 다를 수 있음 */\n\n /* 상속 및 on-demand 연결에서 connection.domain 과 다를 수 있음 */\n if (connection.domain.id !== domain.id) {\n connection.domain = domain\n await connection.disconnect()\n\n /* on-demand 연결인 경우에 connection을 저장하지 말아야 한다. */\n } else {\n await connection.disconnect()\n await repository.save(connection)\n }\n\n return {\n ...connection,\n state: ConnectionManager.getConnectionInstance(connection)\n ? ConnectionStatus.CONNECTED\n : ConnectionStatus.DISCONNECTED\n }\n }\n\n @Directive('@transaction')\n @Directive(\n '@privilege(category: \"connection\", privilege: \"mutation\", domainOwnerGranted: true, superUserGranted: true)'\n )\n @Mutation(returns => Boolean, {\n description: 'Imports multiple connections. Can overwrite existing connections if IDs or names match.'\n })\n async importConnections(\n @Arg('connections', type => [ConnectionPatch]) connections: Connection[],\n @Ctx() context: ResolverContext\n ): Promise<boolean> {\n const { tx, domain, user } = context.state\n\n const repository = tx.getRepository(Connection)\n\n await Promise.all(\n connections.map(async (connection: Connection) => {\n const { id, name } = connection\n\n if (id) {\n const sameId = await repository.findOneBy({ id })\n\n if (sameId) {\n if (sameId.domainId != domain.id) {\n throw `Connection with id '${id}:${name}' is already taken by another domain`\n }\n\n const sameName = await repository.findOneBy({ domain: { id: domain.id }, name })\n if (sameName && sameName.id != id) {\n throw `Connection with name '${name}' is already taken by another connection`\n }\n\n await repository.save({\n ...sameId,\n ...connection,\n ...paramsToStore(connection, sameId),\n domain,\n updater: user\n })\n\n return\n }\n }\n\n await repository.save({\n ...connection,\n ...paramsToStore(connection),\n domain,\n updater: user,\n creator: user\n })\n })\n )\n\n return true\n }\n}\n"]}
|
|
@@ -9,6 +9,15 @@ export declare class ConnectionQuery {
|
|
|
9
9
|
connection(name: string, context: ResolverContext): Promise<Connection>;
|
|
10
10
|
connections(params: ListParam, context: ResolverContext): Promise<ConnectionList>;
|
|
11
11
|
fetchConnectionState(name: string, context: ResolverContext): ConnectionState;
|
|
12
|
+
/**
|
|
13
|
+
* Every read of `Connection.params` passes here — the queries, the mutations' answers and the edge
|
|
14
|
+
* subscriptions alike. Secrets are left out unless the reader is the edge appliance the connection
|
|
15
|
+
* is assigned to (ADR-0112).
|
|
16
|
+
*/
|
|
17
|
+
params(connection: Connection, context: ResolverContext): any;
|
|
18
|
+
secretHints(connection: Connection, context: ResolverContext): {
|
|
19
|
+
[param: string]: string;
|
|
20
|
+
};
|
|
12
21
|
edge(connection: Connection): Promise<Appliance>;
|
|
13
22
|
domain(connection: Connection): Promise<Domain>;
|
|
14
23
|
updater(connection: Connection): Promise<User>;
|
|
@@ -10,6 +10,7 @@ const connection_manager_1 = require("../../engine/connection-manager");
|
|
|
10
10
|
const connection_1 = require("./connection");
|
|
11
11
|
const connection_type_1 = require("./connection-type");
|
|
12
12
|
const domain_inheritance_1 = require("../../utils/domain-inheritance");
|
|
13
|
+
const connection_secrets_1 = require("./connection-secrets");
|
|
13
14
|
/**
|
|
14
15
|
* @description Provides GraphQL resolvers for the Connection entity.
|
|
15
16
|
*/
|
|
@@ -58,6 +59,17 @@ let ConnectionQuery = class ConnectionQuery {
|
|
|
58
59
|
state: connection ? connection_1.ConnectionStatus.CONNECTED : connection_1.ConnectionStatus.DISCONNECTED
|
|
59
60
|
};
|
|
60
61
|
}
|
|
62
|
+
/**
|
|
63
|
+
* Every read of `Connection.params` passes here — the queries, the mutations' answers and the edge
|
|
64
|
+
* subscriptions alike. Secrets are left out unless the reader is the edge appliance the connection
|
|
65
|
+
* is assigned to (ADR-0112).
|
|
66
|
+
*/
|
|
67
|
+
params(connection, context) {
|
|
68
|
+
return (0, connection_secrets_1.paramsVisibleTo)(connection, context?.state?.user);
|
|
69
|
+
}
|
|
70
|
+
secretHints(connection, context) {
|
|
71
|
+
return (0, connection_secrets_1.secretHintsOf)(connection, context?.state?.user);
|
|
72
|
+
}
|
|
61
73
|
async edge(connection) {
|
|
62
74
|
return connection.edgeId && (await (0, shell_1.getRepository)(auth_base_1.Appliance).findOneBy({ id: connection.edgeId }));
|
|
63
75
|
}
|
|
@@ -103,6 +115,28 @@ tslib_1.__decorate([
|
|
|
103
115
|
tslib_1.__metadata("design:paramtypes", [String, Object]),
|
|
104
116
|
tslib_1.__metadata("design:returntype", connection_type_1.ConnectionState)
|
|
105
117
|
], ConnectionQuery.prototype, "fetchConnectionState", null);
|
|
118
|
+
tslib_1.__decorate([
|
|
119
|
+
(0, type_graphql_1.FieldResolver)(type => shell_1.ScalarObject, {
|
|
120
|
+
nullable: true,
|
|
121
|
+
description: "The connection's parameters. Secret parameters are left out except for the edge appliance the connection is assigned to (ADR-0112)."
|
|
122
|
+
}),
|
|
123
|
+
tslib_1.__param(0, (0, type_graphql_1.Root)()),
|
|
124
|
+
tslib_1.__param(1, (0, type_graphql_1.Ctx)()),
|
|
125
|
+
tslib_1.__metadata("design:type", Function),
|
|
126
|
+
tslib_1.__metadata("design:paramtypes", [connection_1.Connection, Object]),
|
|
127
|
+
tslib_1.__metadata("design:returntype", void 0)
|
|
128
|
+
], ConnectionQuery.prototype, "params", null);
|
|
129
|
+
tslib_1.__decorate([
|
|
130
|
+
(0, type_graphql_1.FieldResolver)(type => shell_1.ScalarObject, {
|
|
131
|
+
nullable: true,
|
|
132
|
+
description: 'For each secret parameter still stored in params, the part of its value that may be shown (ADR-0112). Null when there is none.'
|
|
133
|
+
}),
|
|
134
|
+
tslib_1.__param(0, (0, type_graphql_1.Root)()),
|
|
135
|
+
tslib_1.__param(1, (0, type_graphql_1.Ctx)()),
|
|
136
|
+
tslib_1.__metadata("design:type", Function),
|
|
137
|
+
tslib_1.__metadata("design:paramtypes", [connection_1.Connection, Object]),
|
|
138
|
+
tslib_1.__metadata("design:returntype", void 0)
|
|
139
|
+
], ConnectionQuery.prototype, "secretHints", null);
|
|
106
140
|
tslib_1.__decorate([
|
|
107
141
|
(0, type_graphql_1.FieldResolver)(type => shell_1.Domain),
|
|
108
142
|
tslib_1.__param(0, (0, type_graphql_1.Root)()),
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"connection-query.js","sourceRoot":"","sources":["../../../server/service/connection/connection-query.ts"],"names":[],"mappings":"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","sourcesContent":["import { Arg, Args, Ctx, Directive, FieldResolver, Query, Resolver, Root } from 'type-graphql'\nimport { In } from 'typeorm'\n\nimport { Appliance, User } from '@things-factory/auth-base'\nimport { Domain, getQueryBuilderFromListParams, getRepository, ListParam } from '@things-factory/shell'\n\nimport { ConnectionManager } from '../../engine/connection-manager'\nimport { Connection, ConnectionStatus } from './connection'\nimport { ConnectionList, ConnectionState } from './connection-type'\nimport { getDomainIdsWithAncestors } from '../../utils/domain-inheritance'\n\n/**\n * @description Provides GraphQL resolvers for the Connection entity.\n */\n@Resolver(Connection)\nexport class ConnectionQuery {\n @Directive('@privilege(category: \"connection\", privilege: \"query\", domainOwnerGranted: true, superUserGranted: true)')\n @Query(returns => Connection, {\n description: 'Fetches a single connection by its name, including its current state.'\n })\n async connection(@Arg('name') name: string, @Ctx() context: ResolverContext): Promise<Connection> {\n const { domain } = context.state\n const domainIds = await getDomainIdsWithAncestors(domain)\n\n // 동일 name 이 여러 ancestor 도메인에 존재할 수 있음 → closest-first 우선 선택.\n const connections = await getRepository(Connection).find({\n where: { domain: { id: In(domainIds) }, name },\n relations: ['domain']\n })\n\n var connection = connections.sort(\n (a, b) => domainIds.indexOf(a.domainId) - domainIds.indexOf(b.domainId)\n )[0]\n\n return {\n ...connection,\n state: ConnectionManager.getConnectionInstance(connection)\n ? ConnectionStatus.CONNECTED\n : ConnectionStatus.DISCONNECTED\n } as Connection\n }\n\n @Directive('@privilege(category: \"connection\", privilege: \"query\", domainOwnerGranted: true, superUserGranted: true)')\n @Query(returns => ConnectionList, {\n description: 'Fetches a paginated list of connections, including their current states.'\n })\n async connections(\n @Args(type => ListParam) params: ListParam,\n @Ctx() context: ResolverContext\n ): Promise<ConnectionList> {\n const { domain } = context.state\n const domainIds = await getDomainIdsWithAncestors(domain)\n\n const queryBuilder = getQueryBuilderFromListParams({\n repository: getRepository(Connection),\n params,\n // 도메인 필터링은 ancestor 기반으로 직접 적용 (shell helper 는 single-parent 만 지원)\n domain: undefined,\n alias: 'connection',\n searchables: ['name', 'description', 'type', 'endpoint']\n })\n\n queryBuilder.andWhere(`connection.domain IN (:...ancestorDomainIds)`, { ancestorDomainIds: domainIds })\n\n const [items, total] = await queryBuilder.leftJoinAndSelect('connection.domain', 'domain').getManyAndCount()\n\n items.forEach(connection => {\n connection['state'] = ConnectionManager.getConnectionInstance(connection)\n ? ConnectionStatus.CONNECTED\n : ConnectionStatus.DISCONNECTED\n })\n\n return { items, total }\n }\n\n @Directive('@privilege(category: \"connection\", privilege: \"query\", domainOwnerGranted: true, superUserGranted: true)')\n @Query(returns => ConnectionState, { description: 'Fetches the current state of a single connection by its name.' })\n fetchConnectionState(@Arg('name') name: string, @Ctx() context: ResolverContext): ConnectionState {\n const { domain } = context.state\n\n const connection = ConnectionManager.getConnectionInstanceEntityByName(domain, name)\n\n return {\n ...connection,\n state: connection ? ConnectionStatus.CONNECTED : ConnectionStatus.DISCONNECTED\n }\n }\n\n @FieldResolver(type => Domain)\n async edge(@Root() connection: Connection) {\n return connection.edgeId && (await getRepository(Appliance).findOneBy({ id: connection.edgeId }))\n }\n\n @FieldResolver(type => Domain)\n async domain(@Root() connection: Connection) {\n return (\n connection.domain || (connection.domainId && (await getRepository(Domain).findOneBy({ id: connection.domainId })))\n )\n }\n\n @FieldResolver(type => User)\n async updater(@Root() connection: Connection): Promise<User> {\n return connection.updaterId && (await getRepository(User).findOneBy({ id: connection.updaterId }))\n }\n\n @FieldResolver(type => User)\n async creator(@Root() connection: Connection): Promise<User> {\n return connection.creatorId && (await getRepository(User).findOneBy({ id: connection.creatorId }))\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"connection-query.js","sourceRoot":"","sources":["../../../server/service/connection/connection-query.ts"],"names":[],"mappings":"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","sourcesContent":["import { Arg, Args, Ctx, Directive, FieldResolver, Query, Resolver, Root } from 'type-graphql'\nimport { In } from 'typeorm'\n\nimport { Appliance, User } from '@things-factory/auth-base'\nimport { Domain, getQueryBuilderFromListParams, getRepository, ListParam, ScalarObject } from '@things-factory/shell'\n\nimport { ConnectionManager } from '../../engine/connection-manager'\nimport { Connection, ConnectionStatus } from './connection'\nimport { ConnectionList, ConnectionState } from './connection-type'\nimport { getDomainIdsWithAncestors } from '../../utils/domain-inheritance'\nimport { paramsVisibleTo, secretHintsOf } from './connection-secrets'\n\n/**\n * @description Provides GraphQL resolvers for the Connection entity.\n */\n@Resolver(Connection)\nexport class ConnectionQuery {\n @Directive('@privilege(category: \"connection\", privilege: \"query\", domainOwnerGranted: true, superUserGranted: true)')\n @Query(returns => Connection, {\n description: 'Fetches a single connection by its name, including its current state.'\n })\n async connection(@Arg('name') name: string, @Ctx() context: ResolverContext): Promise<Connection> {\n const { domain } = context.state\n const domainIds = await getDomainIdsWithAncestors(domain)\n\n // 동일 name 이 여러 ancestor 도메인에 존재할 수 있음 → closest-first 우선 선택.\n const connections = await getRepository(Connection).find({\n where: { domain: { id: In(domainIds) }, name },\n relations: ['domain']\n })\n\n var connection = connections.sort(\n (a, b) => domainIds.indexOf(a.domainId) - domainIds.indexOf(b.domainId)\n )[0]\n\n return {\n ...connection,\n state: ConnectionManager.getConnectionInstance(connection)\n ? ConnectionStatus.CONNECTED\n : ConnectionStatus.DISCONNECTED\n } as Connection\n }\n\n @Directive('@privilege(category: \"connection\", privilege: \"query\", domainOwnerGranted: true, superUserGranted: true)')\n @Query(returns => ConnectionList, {\n description: 'Fetches a paginated list of connections, including their current states.'\n })\n async connections(\n @Args(type => ListParam) params: ListParam,\n @Ctx() context: ResolverContext\n ): Promise<ConnectionList> {\n const { domain } = context.state\n const domainIds = await getDomainIdsWithAncestors(domain)\n\n const queryBuilder = getQueryBuilderFromListParams({\n repository: getRepository(Connection),\n params,\n // 도메인 필터링은 ancestor 기반으로 직접 적용 (shell helper 는 single-parent 만 지원)\n domain: undefined,\n alias: 'connection',\n searchables: ['name', 'description', 'type', 'endpoint']\n })\n\n queryBuilder.andWhere(`connection.domain IN (:...ancestorDomainIds)`, { ancestorDomainIds: domainIds })\n\n const [items, total] = await queryBuilder.leftJoinAndSelect('connection.domain', 'domain').getManyAndCount()\n\n items.forEach(connection => {\n connection['state'] = ConnectionManager.getConnectionInstance(connection)\n ? ConnectionStatus.CONNECTED\n : ConnectionStatus.DISCONNECTED\n })\n\n return { items, total }\n }\n\n @Directive('@privilege(category: \"connection\", privilege: \"query\", domainOwnerGranted: true, superUserGranted: true)')\n @Query(returns => ConnectionState, { description: 'Fetches the current state of a single connection by its name.' })\n fetchConnectionState(@Arg('name') name: string, @Ctx() context: ResolverContext): ConnectionState {\n const { domain } = context.state\n\n const connection = ConnectionManager.getConnectionInstanceEntityByName(domain, name)\n\n return {\n ...connection,\n state: connection ? ConnectionStatus.CONNECTED : ConnectionStatus.DISCONNECTED\n }\n }\n\n /**\n * Every read of `Connection.params` passes here — the queries, the mutations' answers and the edge\n * subscriptions alike. Secrets are left out unless the reader is the edge appliance the connection\n * is assigned to (ADR-0112).\n */\n @FieldResolver(type => ScalarObject, {\n nullable: true,\n description:\n \"The connection's parameters. Secret parameters are left out except for the edge appliance the connection is assigned to (ADR-0112).\"\n })\n params(@Root() connection: Connection, @Ctx() context: ResolverContext) {\n return paramsVisibleTo(connection, context?.state?.user)\n }\n\n @FieldResolver(type => ScalarObject, {\n nullable: true,\n description:\n 'For each secret parameter still stored in params, the part of its value that may be shown (ADR-0112). Null when there is none.'\n })\n secretHints(@Root() connection: Connection, @Ctx() context: ResolverContext) {\n return secretHintsOf(connection, context?.state?.user)\n }\n\n @FieldResolver(type => Domain)\n async edge(@Root() connection: Connection) {\n return connection.edgeId && (await getRepository(Appliance).findOneBy({ id: connection.edgeId }))\n }\n\n @FieldResolver(type => Domain)\n async domain(@Root() connection: Connection) {\n return (\n connection.domain || (connection.domainId && (await getRepository(Domain).findOneBy({ id: connection.domainId })))\n )\n }\n\n @FieldResolver(type => User)\n async updater(@Root() connection: Connection): Promise<User> {\n return connection.updaterId && (await getRepository(User).findOneBy({ id: connection.updaterId }))\n }\n\n @FieldResolver(type => User)\n async creator(@Root() connection: Connection): Promise<User> {\n return connection.creatorId && (await getRepository(User).findOneBy({ id: connection.creatorId }))\n }\n}\n"]}
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* **A connection's secrets live in EnvVar, never in `params`** (ADR-0112).
|
|
3
|
+
*
|
|
4
|
+
* ── What was wrong ────────────────────────────────────────────────────────
|
|
5
|
+
* `Connection.params` is plain JSON in the database. A password typed into it was kept as it was,
|
|
6
|
+
* handed back by `connections { items { params } }` to anyone who may read connections, and written
|
|
7
|
+
* into the screen's export file. EnvVar already had the right shape — always encrypted at rest
|
|
8
|
+
* (`encryptTransformer`), resolved closest-domain-first by `Connection.getParameter` — but nothing
|
|
9
|
+
* stopped a secret from going into `params` instead.
|
|
10
|
+
*
|
|
11
|
+
* ── Which parameter is a secret ───────────────────────────────────────────
|
|
12
|
+
* One marker: the connector's `parameterSpec` says `type: 'secret'`. Not the name — a name rule
|
|
13
|
+
* catches `keepalive` and `sshKeyPath` and misses `pass`. A test walks every registered connector so a
|
|
14
|
+
* secret written as `string` turns red, and so does a secret without `useDomainAttribute` (it would
|
|
15
|
+
* have nowhere left to go).
|
|
16
|
+
*
|
|
17
|
+
* ── Three things this file does ───────────────────────────────────────────
|
|
18
|
+
* refuse a write that carries a value for a secret parameter is refused, naming the EnvVar key
|
|
19
|
+
* keep a write that leaves a secret out keeps what the row already holds — rows written
|
|
20
|
+
* before this rule still connect, and the masked value a screen read back cannot erase it
|
|
21
|
+
* mask reading `params` leaves secrets out, except for the edge appliance the connection is
|
|
22
|
+
* assigned to, which has to receive them to connect
|
|
23
|
+
*/
|
|
24
|
+
/**
|
|
25
|
+
* The names of the secret parameters of a connector, or `null` when the connector is not registered
|
|
26
|
+
* here. `null` is "cannot tell", not "none": a caller must not read it as "nothing to hide".
|
|
27
|
+
*/
|
|
28
|
+
export declare function secretParamNames(type: string): string[] | null;
|
|
29
|
+
export declare function envVarKeyOf(connectionName: string, param: string): string;
|
|
30
|
+
/**
|
|
31
|
+
* Refuses a write whose `params` hold a value for a secret parameter.
|
|
32
|
+
*
|
|
33
|
+
* Only what the caller sends is checked. A row that already holds a secret is read as before
|
|
34
|
+
* (decision 1 of ADR-0112 - no flag day); it changes when someone writes it.
|
|
35
|
+
*/
|
|
36
|
+
export declare function refuseSecretParams(type: string, connectionName: string, params: {
|
|
37
|
+
[key: string]: any;
|
|
38
|
+
} | null): void;
|
|
39
|
+
/**
|
|
40
|
+
* The `params` to store for a write: what the caller sent, with each secret it left out taken from
|
|
41
|
+
* the stored row.
|
|
42
|
+
*
|
|
43
|
+
* A screen reads `params` with the secrets removed, so saving that object back must not erase a
|
|
44
|
+
* secret a row written before ADR-0112 still holds - that connection would stop on its next connect.
|
|
45
|
+
*/
|
|
46
|
+
export declare function keepStoredSecrets(type: string, incoming: {
|
|
47
|
+
[key: string]: any;
|
|
48
|
+
} | null | undefined, stored: {
|
|
49
|
+
[key: string]: any;
|
|
50
|
+
} | null | undefined): {
|
|
51
|
+
[key: string]: any;
|
|
52
|
+
} | null | undefined;
|
|
53
|
+
/**
|
|
54
|
+
* `params` with the secrets of `type` removed - what may outlive a change of connector type.
|
|
55
|
+
* `null` when `type` is not registered here: nothing can be told apart, so nothing is kept.
|
|
56
|
+
*/
|
|
57
|
+
export declare function withoutSecretsOf(type: string, params: {
|
|
58
|
+
[key: string]: any;
|
|
59
|
+
} | null | undefined): {
|
|
60
|
+
[key: string]: any;
|
|
61
|
+
};
|
|
62
|
+
type Reader = {
|
|
63
|
+
userType?: string;
|
|
64
|
+
reference?: string;
|
|
65
|
+
} | null | undefined;
|
|
66
|
+
/**
|
|
67
|
+
* Whether this reader is the edge appliance the connection is assigned to.
|
|
68
|
+
*
|
|
69
|
+
* Decided by the authenticated principal only (ADR-0112 condition 3): the appliance's shadow user
|
|
70
|
+
* carries the appliance id in `reference`, and the connection names its appliance in `edgeId`.
|
|
71
|
+
* Nothing the request says about itself takes part.
|
|
72
|
+
*/
|
|
73
|
+
export declare function isAssignedEdge(connection: {
|
|
74
|
+
edgeId?: string;
|
|
75
|
+
} | null | undefined, reader: Reader): boolean;
|
|
76
|
+
/**
|
|
77
|
+
* `params` as this reader may see them.
|
|
78
|
+
*
|
|
79
|
+
* The edge subscriptions hand `params` over as a JSON string, so a string comes back a string.
|
|
80
|
+
* A connector that is not registered here cannot say which parameters are secret, so nothing of its
|
|
81
|
+
* `params` is shown - an unknown is not read as "nothing secret".
|
|
82
|
+
*/
|
|
83
|
+
export declare function paramsVisibleTo(connection: {
|
|
84
|
+
type?: string;
|
|
85
|
+
edgeId?: string;
|
|
86
|
+
params?: any;
|
|
87
|
+
} | null | undefined, reader: Reader): any;
|
|
88
|
+
/**
|
|
89
|
+
* For each secret still held in `params` - written before ADR-0112 - the part that may be shown.
|
|
90
|
+
*
|
|
91
|
+
* Reading `params` leaves those secrets out, so the field on the screen is empty while the connection
|
|
92
|
+
* keeps connecting with the old value. The screen shows these as the field's placeholder: the person
|
|
93
|
+
* sees that a value is in use, and saving the form sends nothing back - a placeholder is not a value.
|
|
94
|
+
*
|
|
95
|
+
* `null` when there is none, and for a reader who receives `params` whole (the assigned edge).
|
|
96
|
+
*/
|
|
97
|
+
export declare function secretHintsOf(connection: {
|
|
98
|
+
type?: string;
|
|
99
|
+
edgeId?: string;
|
|
100
|
+
params?: any;
|
|
101
|
+
} | null | undefined, reader: Reader): {
|
|
102
|
+
[param: string]: string;
|
|
103
|
+
} | null;
|
|
104
|
+
export {};
|
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.secretParamNames = secretParamNames;
|
|
4
|
+
exports.envVarKeyOf = envVarKeyOf;
|
|
5
|
+
exports.refuseSecretParams = refuseSecretParams;
|
|
6
|
+
exports.keepStoredSecrets = keepStoredSecrets;
|
|
7
|
+
exports.withoutSecretsOf = withoutSecretsOf;
|
|
8
|
+
exports.isAssignedEdge = isAssignedEdge;
|
|
9
|
+
exports.paramsVisibleTo = paramsVisibleTo;
|
|
10
|
+
exports.secretHintsOf = secretHintsOf;
|
|
11
|
+
const shell_1 = require("@things-factory/shell");
|
|
12
|
+
const connection_manager_1 = require("../../engine/connection-manager");
|
|
13
|
+
const secret_hint_1 = require("../secret-hint");
|
|
14
|
+
/**
|
|
15
|
+
* **A connection's secrets live in EnvVar, never in `params`** (ADR-0112).
|
|
16
|
+
*
|
|
17
|
+
* ── What was wrong ────────────────────────────────────────────────────────
|
|
18
|
+
* `Connection.params` is plain JSON in the database. A password typed into it was kept as it was,
|
|
19
|
+
* handed back by `connections { items { params } }` to anyone who may read connections, and written
|
|
20
|
+
* into the screen's export file. EnvVar already had the right shape — always encrypted at rest
|
|
21
|
+
* (`encryptTransformer`), resolved closest-domain-first by `Connection.getParameter` — but nothing
|
|
22
|
+
* stopped a secret from going into `params` instead.
|
|
23
|
+
*
|
|
24
|
+
* ── Which parameter is a secret ───────────────────────────────────────────
|
|
25
|
+
* One marker: the connector's `parameterSpec` says `type: 'secret'`. Not the name — a name rule
|
|
26
|
+
* catches `keepalive` and `sshKeyPath` and misses `pass`. A test walks every registered connector so a
|
|
27
|
+
* secret written as `string` turns red, and so does a secret without `useDomainAttribute` (it would
|
|
28
|
+
* have nowhere left to go).
|
|
29
|
+
*
|
|
30
|
+
* ── Three things this file does ───────────────────────────────────────────
|
|
31
|
+
* refuse a write that carries a value for a secret parameter is refused, naming the EnvVar key
|
|
32
|
+
* keep a write that leaves a secret out keeps what the row already holds — rows written
|
|
33
|
+
* before this rule still connect, and the masked value a screen read back cannot erase it
|
|
34
|
+
* mask reading `params` leaves secrets out, except for the edge appliance the connection is
|
|
35
|
+
* assigned to, which has to receive them to connect
|
|
36
|
+
*/
|
|
37
|
+
/**
|
|
38
|
+
* The names of the secret parameters of a connector, or `null` when the connector is not registered
|
|
39
|
+
* here. `null` is "cannot tell", not "none": a caller must not read it as "nothing to hide".
|
|
40
|
+
*/
|
|
41
|
+
function secretParamNames(type) {
|
|
42
|
+
const connector = type ? connection_manager_1.ConnectionManager.getConnector(type) : null;
|
|
43
|
+
if (!connector) {
|
|
44
|
+
return null;
|
|
45
|
+
}
|
|
46
|
+
return (connector.parameterSpec || []).filter(spec => spec?.type === 'secret').map(spec => spec.name);
|
|
47
|
+
}
|
|
48
|
+
function envVarKeyOf(connectionName, param) {
|
|
49
|
+
return `Connection::${connectionName}::${param}`;
|
|
50
|
+
}
|
|
51
|
+
function present(value) {
|
|
52
|
+
return value !== null && value !== undefined && value !== '';
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Refuses a write whose `params` hold a value for a secret parameter.
|
|
56
|
+
*
|
|
57
|
+
* Only what the caller sends is checked. A row that already holds a secret is read as before
|
|
58
|
+
* (decision 1 of ADR-0112 - no flag day); it changes when someone writes it.
|
|
59
|
+
*/
|
|
60
|
+
function refuseSecretParams(type, connectionName, params) {
|
|
61
|
+
if (!params || typeof params !== 'object') {
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
for (const param of secretParamNames(type) || []) {
|
|
65
|
+
if (present(params[param])) {
|
|
66
|
+
const envVar = envVarKeyOf(connectionName, param);
|
|
67
|
+
throw new shell_1.Refusal('connection-secret-in-params', { connection: connectionName, param, envVar }, `"${param}" of connection "${connectionName}" is a secret and is not stored in the connection. ` +
|
|
68
|
+
`Set it as the environment variable "${envVar}".`);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* The `params` to store for a write: what the caller sent, with each secret it left out taken from
|
|
74
|
+
* the stored row.
|
|
75
|
+
*
|
|
76
|
+
* A screen reads `params` with the secrets removed, so saving that object back must not erase a
|
|
77
|
+
* secret a row written before ADR-0112 still holds - that connection would stop on its next connect.
|
|
78
|
+
*/
|
|
79
|
+
function keepStoredSecrets(type, incoming, stored) {
|
|
80
|
+
if (!incoming || typeof incoming !== 'object' || !stored || typeof stored !== 'object') {
|
|
81
|
+
return incoming;
|
|
82
|
+
}
|
|
83
|
+
const kept = { ...incoming };
|
|
84
|
+
for (const param of secretParamNames(type) || []) {
|
|
85
|
+
if (!present(kept[param]) && present(stored[param])) {
|
|
86
|
+
kept[param] = stored[param];
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
return kept;
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* `params` with the secrets of `type` removed - what may outlive a change of connector type.
|
|
93
|
+
* `null` when `type` is not registered here: nothing can be told apart, so nothing is kept.
|
|
94
|
+
*/
|
|
95
|
+
function withoutSecretsOf(type, params) {
|
|
96
|
+
const secrets = secretParamNames(type);
|
|
97
|
+
if (!secrets) {
|
|
98
|
+
return null;
|
|
99
|
+
}
|
|
100
|
+
if (!params || typeof params !== 'object') {
|
|
101
|
+
return params;
|
|
102
|
+
}
|
|
103
|
+
const kept = { ...params };
|
|
104
|
+
for (const param of secrets) {
|
|
105
|
+
delete kept[param];
|
|
106
|
+
}
|
|
107
|
+
return kept;
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* Whether this reader is the edge appliance the connection is assigned to.
|
|
111
|
+
*
|
|
112
|
+
* Decided by the authenticated principal only (ADR-0112 condition 3): the appliance's shadow user
|
|
113
|
+
* carries the appliance id in `reference`, and the connection names its appliance in `edgeId`.
|
|
114
|
+
* Nothing the request says about itself takes part.
|
|
115
|
+
*/
|
|
116
|
+
function isAssignedEdge(connection, reader) {
|
|
117
|
+
return Boolean(reader?.userType === 'appliance' && reader.reference && connection?.edgeId && connection.edgeId === reader.reference);
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* `params` as this reader may see them.
|
|
121
|
+
*
|
|
122
|
+
* The edge subscriptions hand `params` over as a JSON string, so a string comes back a string.
|
|
123
|
+
* A connector that is not registered here cannot say which parameters are secret, so nothing of its
|
|
124
|
+
* `params` is shown - an unknown is not read as "nothing secret".
|
|
125
|
+
*/
|
|
126
|
+
function paramsVisibleTo(connection, reader) {
|
|
127
|
+
const params = connection?.params;
|
|
128
|
+
if (params === null || params === undefined || isAssignedEdge(connection, reader)) {
|
|
129
|
+
return params;
|
|
130
|
+
}
|
|
131
|
+
const secrets = secretParamNames(connection.type);
|
|
132
|
+
if (!secrets) {
|
|
133
|
+
return null;
|
|
134
|
+
}
|
|
135
|
+
const asString = typeof params === 'string';
|
|
136
|
+
let object = params;
|
|
137
|
+
if (asString) {
|
|
138
|
+
try {
|
|
139
|
+
object = JSON.parse(params);
|
|
140
|
+
}
|
|
141
|
+
catch (e) {
|
|
142
|
+
return null;
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
if (!object || typeof object !== 'object') {
|
|
146
|
+
return asString ? params : object;
|
|
147
|
+
}
|
|
148
|
+
const visible = { ...object };
|
|
149
|
+
for (const param of secrets) {
|
|
150
|
+
delete visible[param];
|
|
151
|
+
}
|
|
152
|
+
return asString ? JSON.stringify(visible) : visible;
|
|
153
|
+
}
|
|
154
|
+
/**
|
|
155
|
+
* For each secret still held in `params` - written before ADR-0112 - the part that may be shown.
|
|
156
|
+
*
|
|
157
|
+
* Reading `params` leaves those secrets out, so the field on the screen is empty while the connection
|
|
158
|
+
* keeps connecting with the old value. The screen shows these as the field's placeholder: the person
|
|
159
|
+
* sees that a value is in use, and saving the form sends nothing back - a placeholder is not a value.
|
|
160
|
+
*
|
|
161
|
+
* `null` when there is none, and for a reader who receives `params` whole (the assigned edge).
|
|
162
|
+
*/
|
|
163
|
+
function secretHintsOf(connection, reader) {
|
|
164
|
+
if (!connection?.params || isAssignedEdge(connection, reader)) {
|
|
165
|
+
return null;
|
|
166
|
+
}
|
|
167
|
+
let params = connection.params;
|
|
168
|
+
if (typeof params === 'string') {
|
|
169
|
+
try {
|
|
170
|
+
params = JSON.parse(params);
|
|
171
|
+
}
|
|
172
|
+
catch (e) {
|
|
173
|
+
return null;
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
if (!params || typeof params !== 'object') {
|
|
177
|
+
return null;
|
|
178
|
+
}
|
|
179
|
+
const hints = {};
|
|
180
|
+
for (const param of secretParamNames(connection.type) || []) {
|
|
181
|
+
const hint = present(params[param]) ? (0, secret_hint_1.secretHint)(String(params[param])) : undefined;
|
|
182
|
+
if (hint) {
|
|
183
|
+
hints[param] = hint;
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
return Object.keys(hints).length > 0 ? hints : null;
|
|
187
|
+
}
|
|
188
|
+
//# sourceMappingURL=connection-secrets.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"connection-secrets.js","sourceRoot":"","sources":["../../../server/service/connection/connection-secrets.ts"],"names":[],"mappings":"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","sourcesContent":["import { Refusal } from '@things-factory/shell'\n\nimport { ConnectionManager } from '../../engine/connection-manager'\nimport { secretHint } from '../secret-hint'\n\n/**\n * **A connection's secrets live in EnvVar, never in `params`** (ADR-0112).\n *\n * ── What was wrong ────────────────────────────────────────────────────────\n * `Connection.params` is plain JSON in the database. A password typed into it was kept as it was,\n * handed back by `connections { items { params } }` to anyone who may read connections, and written\n * into the screen's export file. EnvVar already had the right shape — always encrypted at rest\n * (`encryptTransformer`), resolved closest-domain-first by `Connection.getParameter` — but nothing\n * stopped a secret from going into `params` instead.\n *\n * ── Which parameter is a secret ───────────────────────────────────────────\n * One marker: the connector's `parameterSpec` says `type: 'secret'`. Not the name — a name rule\n * catches `keepalive` and `sshKeyPath` and misses `pass`. A test walks every registered connector so a\n * secret written as `string` turns red, and so does a secret without `useDomainAttribute` (it would\n * have nowhere left to go).\n *\n * ── Three things this file does ───────────────────────────────────────────\n * refuse a write that carries a value for a secret parameter is refused, naming the EnvVar key\n * keep a write that leaves a secret out keeps what the row already holds — rows written\n * before this rule still connect, and the masked value a screen read back cannot erase it\n * mask reading `params` leaves secrets out, except for the edge appliance the connection is\n * assigned to, which has to receive them to connect\n */\n\n/**\n * The names of the secret parameters of a connector, or `null` when the connector is not registered\n * here. `null` is \"cannot tell\", not \"none\": a caller must not read it as \"nothing to hide\".\n */\nexport function secretParamNames(type: string): string[] | null {\n const connector = type ? ConnectionManager.getConnector(type) : null\n if (!connector) {\n return null\n }\n\n return (connector.parameterSpec || []).filter(spec => spec?.type === 'secret').map(spec => spec.name)\n}\n\nexport function envVarKeyOf(connectionName: string, param: string): string {\n return `Connection::${connectionName}::${param}`\n}\n\nfunction present(value: any): boolean {\n return value !== null && value !== undefined && value !== ''\n}\n\n/**\n * Refuses a write whose `params` hold a value for a secret parameter.\n *\n * Only what the caller sends is checked. A row that already holds a secret is read as before\n * (decision 1 of ADR-0112 - no flag day); it changes when someone writes it.\n */\nexport function refuseSecretParams(type: string, connectionName: string, params: { [key: string]: any } | null) {\n if (!params || typeof params !== 'object') {\n return\n }\n\n for (const param of secretParamNames(type) || []) {\n if (present(params[param])) {\n const envVar = envVarKeyOf(connectionName, param)\n\n throw new Refusal(\n 'connection-secret-in-params',\n { connection: connectionName, param, envVar },\n `\"${param}\" of connection \"${connectionName}\" is a secret and is not stored in the connection. ` +\n `Set it as the environment variable \"${envVar}\".`\n )\n }\n }\n}\n\n/**\n * The `params` to store for a write: what the caller sent, with each secret it left out taken from\n * the stored row.\n *\n * A screen reads `params` with the secrets removed, so saving that object back must not erase a\n * secret a row written before ADR-0112 still holds - that connection would stop on its next connect.\n */\nexport function keepStoredSecrets(\n type: string,\n incoming: { [key: string]: any } | null | undefined,\n stored: { [key: string]: any } | null | undefined\n): { [key: string]: any } | null | undefined {\n if (!incoming || typeof incoming !== 'object' || !stored || typeof stored !== 'object') {\n return incoming\n }\n\n const kept = { ...incoming }\n for (const param of secretParamNames(type) || []) {\n if (!present(kept[param]) && present(stored[param])) {\n kept[param] = stored[param]\n }\n }\n\n return kept\n}\n\n/**\n * `params` with the secrets of `type` removed - what may outlive a change of connector type.\n * `null` when `type` is not registered here: nothing can be told apart, so nothing is kept.\n */\nexport function withoutSecretsOf(type: string, params: { [key: string]: any } | null | undefined) {\n const secrets = secretParamNames(type)\n if (!secrets) {\n return null\n }\n if (!params || typeof params !== 'object') {\n return params\n }\n\n const kept = { ...params }\n for (const param of secrets) {\n delete kept[param]\n }\n return kept\n}\n\ntype Reader = { userType?: string; reference?: string } | null | undefined\n\n/**\n * Whether this reader is the edge appliance the connection is assigned to.\n *\n * Decided by the authenticated principal only (ADR-0112 condition 3): the appliance's shadow user\n * carries the appliance id in `reference`, and the connection names its appliance in `edgeId`.\n * Nothing the request says about itself takes part.\n */\nexport function isAssignedEdge(connection: { edgeId?: string } | null | undefined, reader: Reader): boolean {\n return Boolean(\n reader?.userType === 'appliance' && reader.reference && connection?.edgeId && connection.edgeId === reader.reference\n )\n}\n\n/**\n * `params` as this reader may see them.\n *\n * The edge subscriptions hand `params` over as a JSON string, so a string comes back a string.\n * A connector that is not registered here cannot say which parameters are secret, so nothing of its\n * `params` is shown - an unknown is not read as \"nothing secret\".\n */\nexport function paramsVisibleTo(\n connection: { type?: string; edgeId?: string; params?: any } | null | undefined,\n reader: Reader\n): any {\n const params = connection?.params\n if (params === null || params === undefined || isAssignedEdge(connection, reader)) {\n return params\n }\n\n const secrets = secretParamNames(connection.type)\n if (!secrets) {\n return null\n }\n\n const asString = typeof params === 'string'\n let object: any = params\n if (asString) {\n try {\n object = JSON.parse(params)\n } catch (e) {\n return null\n }\n }\n\n if (!object || typeof object !== 'object') {\n return asString ? params : object\n }\n\n const visible = { ...object }\n for (const param of secrets) {\n delete visible[param]\n }\n\n return asString ? JSON.stringify(visible) : visible\n}\n\n/**\n * For each secret still held in `params` - written before ADR-0112 - the part that may be shown.\n *\n * Reading `params` leaves those secrets out, so the field on the screen is empty while the connection\n * keeps connecting with the old value. The screen shows these as the field's placeholder: the person\n * sees that a value is in use, and saving the form sends nothing back - a placeholder is not a value.\n *\n * `null` when there is none, and for a reader who receives `params` whole (the assigned edge).\n */\nexport function secretHintsOf(\n connection: { type?: string; edgeId?: string; params?: any } | null | undefined,\n reader: Reader\n): { [param: string]: string } | null {\n if (!connection?.params || isAssignedEdge(connection, reader)) {\n return null\n }\n\n let params: any = connection.params\n if (typeof params === 'string') {\n try {\n params = JSON.parse(params)\n } catch (e) {\n return null\n }\n }\n if (!params || typeof params !== 'object') {\n return null\n }\n\n const hints: { [param: string]: string } = {}\n for (const param of secretParamNames(connection.type) || []) {\n const hint = present(params[param]) ? secretHint(String(params[param])) : undefined\n if (hint) {\n hints[param] = hint\n }\n }\n\n return Object.keys(hints).length > 0 ? hints : null\n}\n"]}
|