jazz-tools 0.10.6 → 0.10.7
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/.turbo/turbo-build.log +6 -6
- package/CHANGELOG.md +10 -0
- package/dist/{chunk-DPW23T6J.js → chunk-TSEO4KAO.js} +23 -7
- package/dist/chunk-TSEO4KAO.js.map +1 -0
- package/dist/index.js +1 -1
- package/dist/testing.js +21 -13
- package/dist/testing.js.map +1 -1
- package/package.json +2 -2
- package/src/auth/AuthSecretStorage.ts +9 -2
- package/src/implementation/ContextManager.ts +23 -4
- package/src/implementation/createContext.ts +0 -3
- package/src/testing.ts +22 -12
- package/src/tests/AuthSecretStorage.test.ts +192 -66
- package/src/tests/ContextManager.test.ts +14 -9
- package/src/types.ts +2 -0
- package/dist/chunk-DPW23T6J.js.map +0 -1
package/dist/index.js
CHANGED
package/dist/testing.js
CHANGED
@@ -5,7 +5,7 @@ import {
|
|
5
5
|
createAnonymousJazzContext,
|
6
6
|
createJazzContext,
|
7
7
|
randomSessionProvider
|
8
|
-
} from "./chunk-
|
8
|
+
} from "./chunk-TSEO4KAO.js";
|
9
9
|
|
10
10
|
// src/testing.ts
|
11
11
|
import { LocalNode } from "cojson";
|
@@ -108,13 +108,13 @@ var TestJazzContextManager = class _TestJazzContextManager extends JazzContextMa
|
|
108
108
|
const provider = props?.isAuthenticated ? "testProvider" : "anonymous";
|
109
109
|
const storage = context.getAuthSecretStorage();
|
110
110
|
const node = account._raw.core.node;
|
111
|
-
|
111
|
+
const credentials = {
|
112
112
|
accountID: account.id,
|
113
113
|
accountSecret: node.account.agentSecret,
|
114
114
|
secretSeed: SecretSeedMap.get(account.id),
|
115
115
|
provider
|
116
|
-
}
|
117
|
-
storage.
|
116
|
+
};
|
117
|
+
storage.set(credentials);
|
118
118
|
context.updateContext(
|
119
119
|
{
|
120
120
|
AccountSchema: account.constructor,
|
@@ -127,8 +127,12 @@ var TestJazzContextManager = class _TestJazzContextManager extends JazzContextMa
|
|
127
127
|
node.gracefulShutdown();
|
128
128
|
},
|
129
129
|
logOut: async () => {
|
130
|
+
await storage.clear();
|
130
131
|
node.gracefulShutdown();
|
131
132
|
}
|
133
|
+
},
|
134
|
+
{
|
135
|
+
credentials
|
132
136
|
}
|
133
137
|
);
|
134
138
|
return context;
|
@@ -165,16 +169,20 @@ var TestJazzContextManager = class _TestJazzContextManager extends JazzContextMa
|
|
165
169
|
authSecretStorage: this.getAuthSecretStorage(),
|
166
170
|
AccountSchema: props.AccountSchema
|
167
171
|
});
|
168
|
-
this.updateContext(
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
context.
|
172
|
+
await this.updateContext(
|
173
|
+
props,
|
174
|
+
{
|
175
|
+
me: context.account,
|
176
|
+
node: context.node,
|
177
|
+
done: () => {
|
178
|
+
context.done();
|
179
|
+
},
|
180
|
+
logOut: () => {
|
181
|
+
return context.logOut();
|
182
|
+
}
|
173
183
|
},
|
174
|
-
|
175
|
-
|
176
|
-
}
|
177
|
-
});
|
184
|
+
authProps
|
185
|
+
);
|
178
186
|
}
|
179
187
|
};
|
180
188
|
function linkAccounts(a, b, aRole = "server", bRole = "server") {
|
package/dist/testing.js.map
CHANGED
@@ -1 +1 @@
|
|
1
|
-
{"version":3,"sources":["../src/testing.ts"],"sourcesContent":["import { AgentSecret, CryptoProvider, LocalNode, Peer } from \"cojson\";\nimport { cojsonInternals } from \"cojson\";\nimport { PureJSCrypto } from \"cojson/dist/crypto/PureJSCrypto\";\nimport {\n Account,\n AccountClass,\n JazzContextManagerAuthProps,\n} from \"./exports.js\";\nimport {\n JazzContextManager,\n JazzContextManagerBaseProps,\n} from \"./implementation/ContextManager.js\";\nimport { activeAccountContext } from \"./implementation/activeAccountContext.js\";\nimport {\n type AnonymousJazzAgent,\n type CoValueClass,\n createAnonymousJazzContext,\n createJazzContext,\n randomSessionProvider,\n} from \"./internal.js\";\n\nconst syncServer: { current: LocalNode | null } = { current: null };\n\ntype TestAccountSchema<Acc extends Account> = CoValueClass<Acc> & {\n fromNode: (typeof Account)[\"fromNode\"];\n create: (options: {\n creationProps: { name: string };\n initialAgentSecret?: AgentSecret;\n peersToLoadFrom?: Peer[];\n crypto: CryptoProvider;\n }) => Promise<Acc>;\n};\n\nexport class TestJSCrypto extends PureJSCrypto {\n static async create() {\n if (\"navigator\" in globalThis && navigator.userAgent?.includes(\"jsdom\")) {\n // Mocking crypto seal & encrypt to make it work with JSDom. Getting \"Error: Uint8Array expected\" there\n const crypto = new PureJSCrypto();\n\n crypto.seal = (options) =>\n `sealed_U${cojsonInternals.stableStringify(options.message)}` as any;\n crypto.unseal = (sealed) =>\n JSON.parse(sealed.substring(\"sealed_U\".length));\n crypto.encrypt = (message) =>\n `encrypted_U${cojsonInternals.stableStringify(message)}` as any;\n crypto.decryptRaw = (encrypted) =>\n encrypted.substring(\"encrypted_U\".length) as any;\n\n return crypto;\n }\n\n // For non-jsdom environments, we use the real crypto\n return new PureJSCrypto();\n }\n}\n\nexport function getPeerConnectedToTestSyncServer() {\n if (!syncServer.current) {\n throw new Error(\"Sync server not initialized\");\n }\n\n const [aPeer, bPeer] = cojsonInternals.connectedPeers(\n Math.random().toString(),\n Math.random().toString(),\n {\n peer1role: \"server\",\n peer2role: \"server\",\n },\n );\n syncServer.current.syncManager.addPeer(aPeer);\n\n return bPeer;\n}\n\nconst SecretSeedMap = new Map<string, Uint8Array>();\nlet isMigrationActive = false;\n\nexport async function createJazzTestAccount<Acc extends Account>(options?: {\n isCurrentActiveAccount?: boolean;\n AccountSchema?: CoValueClass<Acc>;\n creationProps?: Record<string, unknown>;\n}): Promise<Acc> {\n const AccountSchema = (options?.AccountSchema ??\n Account) as unknown as TestAccountSchema<Acc>;\n const peers = [];\n if (syncServer.current) {\n peers.push(getPeerConnectedToTestSyncServer());\n }\n\n const crypto = await TestJSCrypto.create();\n const secretSeed = crypto.newRandomSecretSeed();\n\n const { node } = await LocalNode.withNewlyCreatedAccount({\n creationProps: {\n name: \"Test Account\",\n ...options?.creationProps,\n },\n initialAgentSecret: crypto.agentSecretFromSecretSeed(secretSeed),\n crypto,\n peersToLoadFrom: peers,\n migration: async (rawAccount, _node, creationProps) => {\n if (isMigrationActive) {\n throw new Error(\n \"It is not possible to create multiple accounts in parallel inside the test environment.\",\n );\n }\n\n isMigrationActive = true;\n\n const account = new AccountSchema({\n fromRaw: rawAccount,\n });\n\n // We need to set the account as current because the migration\n // will probably rely on the global me\n const prevActiveAccount = activeAccountContext.maybeGet();\n activeAccountContext.set(account);\n\n await account.applyMigration?.(creationProps);\n\n if (!options?.isCurrentActiveAccount) {\n activeAccountContext.set(prevActiveAccount);\n }\n\n isMigrationActive = false;\n },\n });\n\n const account = AccountSchema.fromNode(node);\n SecretSeedMap.set(account.id, secretSeed);\n\n if (options?.isCurrentActiveAccount) {\n activeAccountContext.set(account);\n }\n\n return account;\n}\n\nexport function setActiveAccount(account: Account) {\n activeAccountContext.set(account);\n}\n\nexport async function createJazzTestGuest() {\n const ctx = await createAnonymousJazzContext({\n crypto: await PureJSCrypto.create(),\n peersToLoadFrom: [],\n });\n\n return {\n guest: ctx.agent,\n };\n}\n\nexport type TestJazzContextManagerProps<Acc extends Account> =\n JazzContextManagerBaseProps<Acc> & {\n defaultProfileName?: string;\n AccountSchema?: AccountClass<Acc>;\n isAuthenticated?: boolean;\n };\n\nexport class TestJazzContextManager<\n Acc extends Account,\n> extends JazzContextManager<Acc, TestJazzContextManagerProps<Acc>> {\n static fromAccountOrGuest<Acc extends Account>(\n account?: Acc | { guest: AnonymousJazzAgent },\n props?: TestJazzContextManagerProps<Acc>,\n ) {\n if (account && \"guest\" in account) {\n return this.fromGuest<Acc>(account, props);\n }\n\n return this.fromAccount<Acc>(account ?? (Account.getMe() as Acc), props);\n }\n\n static fromAccount<Acc extends Account>(\n account: Acc,\n props?: TestJazzContextManagerProps<Acc>,\n ) {\n const context = new TestJazzContextManager<Acc>();\n\n const provider = props?.isAuthenticated ? \"testProvider\" : \"anonymous\";\n const storage = context.getAuthSecretStorage();\n const node = account._raw.core.node;\n\n storage.set({\n accountID: account.id,\n accountSecret: node.account.agentSecret,\n secretSeed: SecretSeedMap.get(account.id),\n provider,\n });\n storage.isAuthenticated = Boolean(props?.isAuthenticated);\n\n context.updateContext(\n {\n AccountSchema: account.constructor as AccountClass<Acc>,\n ...props,\n },\n {\n me: account,\n node,\n done: () => {\n node.gracefulShutdown();\n },\n logOut: async () => {\n node.gracefulShutdown();\n },\n },\n );\n\n return context;\n }\n\n static fromGuest<Acc extends Account>(\n { guest }: { guest: AnonymousJazzAgent },\n props: TestJazzContextManagerProps<Acc> = {},\n ) {\n const context = new TestJazzContextManager<Acc>();\n const node = guest.node;\n\n context.updateContext(props, {\n guest,\n node,\n done: () => {\n node.gracefulShutdown();\n },\n logOut: async () => {\n node.gracefulShutdown();\n },\n });\n\n return context;\n }\n\n async createContext(\n props: TestJazzContextManagerProps<Acc>,\n authProps?: JazzContextManagerAuthProps,\n ) {\n this.props = props;\n\n if (!syncServer.current) {\n throw new Error(\n \"You need to setup a test sync server with setupJazzTestSync to use the Auth functions\",\n );\n }\n\n const context = await createJazzContext<Acc>({\n credentials: authProps?.credentials,\n defaultProfileName: props.defaultProfileName,\n newAccountProps: authProps?.newAccountProps,\n peersToLoadFrom: [getPeerConnectedToTestSyncServer()],\n crypto: await TestJSCrypto.create(),\n sessionProvider: randomSessionProvider,\n authSecretStorage: this.getAuthSecretStorage(),\n AccountSchema: props.AccountSchema,\n });\n\n this.updateContext(props, {\n me: context.account,\n node: context.node,\n done: () => {\n context.done();\n },\n logOut: () => {\n return context.logOut();\n },\n });\n }\n}\n\nexport function linkAccounts(\n a: Account,\n b: Account,\n aRole: \"server\" | \"client\" = \"server\",\n bRole: \"server\" | \"client\" = \"server\",\n) {\n const [aPeer, bPeer] = cojsonInternals.connectedPeers(b.id, a.id, {\n peer1role: aRole,\n peer2role: bRole,\n });\n\n a._raw.core.node.syncManager.addPeer(aPeer);\n b._raw.core.node.syncManager.addPeer(bPeer);\n}\n\nexport async function setupJazzTestSync() {\n if (syncServer.current) {\n syncServer.current.gracefulShutdown();\n }\n\n const account = await Account.create({\n creationProps: {\n name: \"Test Account\",\n },\n crypto: await TestJSCrypto.create(),\n });\n\n syncServer.current = account._raw.core.node;\n\n return account;\n}\n"],"mappings":"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","names":["account"]}
|
1
|
+
{"version":3,"sources":["../src/testing.ts"],"sourcesContent":["import { AgentSecret, CryptoProvider, LocalNode, Peer } from \"cojson\";\nimport { cojsonInternals } from \"cojson\";\nimport { PureJSCrypto } from \"cojson/dist/crypto/PureJSCrypto\";\nimport {\n Account,\n AccountClass,\n AuthCredentials,\n JazzContextManagerAuthProps,\n} from \"./exports.js\";\nimport {\n JazzContextManager,\n JazzContextManagerBaseProps,\n} from \"./implementation/ContextManager.js\";\nimport { activeAccountContext } from \"./implementation/activeAccountContext.js\";\nimport {\n type AnonymousJazzAgent,\n type CoValueClass,\n createAnonymousJazzContext,\n createJazzContext,\n randomSessionProvider,\n} from \"./internal.js\";\n\nconst syncServer: { current: LocalNode | null } = { current: null };\n\ntype TestAccountSchema<Acc extends Account> = CoValueClass<Acc> & {\n fromNode: (typeof Account)[\"fromNode\"];\n create: (options: {\n creationProps: { name: string };\n initialAgentSecret?: AgentSecret;\n peersToLoadFrom?: Peer[];\n crypto: CryptoProvider;\n }) => Promise<Acc>;\n};\n\nexport class TestJSCrypto extends PureJSCrypto {\n static async create() {\n if (\"navigator\" in globalThis && navigator.userAgent?.includes(\"jsdom\")) {\n // Mocking crypto seal & encrypt to make it work with JSDom. Getting \"Error: Uint8Array expected\" there\n const crypto = new PureJSCrypto();\n\n crypto.seal = (options) =>\n `sealed_U${cojsonInternals.stableStringify(options.message)}` as any;\n crypto.unseal = (sealed) =>\n JSON.parse(sealed.substring(\"sealed_U\".length));\n crypto.encrypt = (message) =>\n `encrypted_U${cojsonInternals.stableStringify(message)}` as any;\n crypto.decryptRaw = (encrypted) =>\n encrypted.substring(\"encrypted_U\".length) as any;\n\n return crypto;\n }\n\n // For non-jsdom environments, we use the real crypto\n return new PureJSCrypto();\n }\n}\n\nexport function getPeerConnectedToTestSyncServer() {\n if (!syncServer.current) {\n throw new Error(\"Sync server not initialized\");\n }\n\n const [aPeer, bPeer] = cojsonInternals.connectedPeers(\n Math.random().toString(),\n Math.random().toString(),\n {\n peer1role: \"server\",\n peer2role: \"server\",\n },\n );\n syncServer.current.syncManager.addPeer(aPeer);\n\n return bPeer;\n}\n\nconst SecretSeedMap = new Map<string, Uint8Array>();\nlet isMigrationActive = false;\n\nexport async function createJazzTestAccount<Acc extends Account>(options?: {\n isCurrentActiveAccount?: boolean;\n AccountSchema?: CoValueClass<Acc>;\n creationProps?: Record<string, unknown>;\n}): Promise<Acc> {\n const AccountSchema = (options?.AccountSchema ??\n Account) as unknown as TestAccountSchema<Acc>;\n const peers = [];\n if (syncServer.current) {\n peers.push(getPeerConnectedToTestSyncServer());\n }\n\n const crypto = await TestJSCrypto.create();\n const secretSeed = crypto.newRandomSecretSeed();\n\n const { node } = await LocalNode.withNewlyCreatedAccount({\n creationProps: {\n name: \"Test Account\",\n ...options?.creationProps,\n },\n initialAgentSecret: crypto.agentSecretFromSecretSeed(secretSeed),\n crypto,\n peersToLoadFrom: peers,\n migration: async (rawAccount, _node, creationProps) => {\n if (isMigrationActive) {\n throw new Error(\n \"It is not possible to create multiple accounts in parallel inside the test environment.\",\n );\n }\n\n isMigrationActive = true;\n\n const account = new AccountSchema({\n fromRaw: rawAccount,\n });\n\n // We need to set the account as current because the migration\n // will probably rely on the global me\n const prevActiveAccount = activeAccountContext.maybeGet();\n activeAccountContext.set(account);\n\n await account.applyMigration?.(creationProps);\n\n if (!options?.isCurrentActiveAccount) {\n activeAccountContext.set(prevActiveAccount);\n }\n\n isMigrationActive = false;\n },\n });\n\n const account = AccountSchema.fromNode(node);\n SecretSeedMap.set(account.id, secretSeed);\n\n if (options?.isCurrentActiveAccount) {\n activeAccountContext.set(account);\n }\n\n return account;\n}\n\nexport function setActiveAccount(account: Account) {\n activeAccountContext.set(account);\n}\n\nexport async function createJazzTestGuest() {\n const ctx = await createAnonymousJazzContext({\n crypto: await PureJSCrypto.create(),\n peersToLoadFrom: [],\n });\n\n return {\n guest: ctx.agent,\n };\n}\n\nexport type TestJazzContextManagerProps<Acc extends Account> =\n JazzContextManagerBaseProps<Acc> & {\n defaultProfileName?: string;\n AccountSchema?: AccountClass<Acc>;\n isAuthenticated?: boolean;\n };\n\nexport class TestJazzContextManager<\n Acc extends Account,\n> extends JazzContextManager<Acc, TestJazzContextManagerProps<Acc>> {\n static fromAccountOrGuest<Acc extends Account>(\n account?: Acc | { guest: AnonymousJazzAgent },\n props?: TestJazzContextManagerProps<Acc>,\n ) {\n if (account && \"guest\" in account) {\n return this.fromGuest<Acc>(account, props);\n }\n\n return this.fromAccount<Acc>(account ?? (Account.getMe() as Acc), props);\n }\n\n static fromAccount<Acc extends Account>(\n account: Acc,\n props?: TestJazzContextManagerProps<Acc>,\n ) {\n const context = new TestJazzContextManager<Acc>();\n\n const provider = props?.isAuthenticated ? \"testProvider\" : \"anonymous\";\n const storage = context.getAuthSecretStorage();\n const node = account._raw.core.node;\n\n const credentials = {\n accountID: account.id,\n accountSecret: node.account.agentSecret,\n secretSeed: SecretSeedMap.get(account.id),\n provider,\n } satisfies AuthCredentials;\n\n storage.set(credentials);\n\n context.updateContext(\n {\n AccountSchema: account.constructor as AccountClass<Acc>,\n ...props,\n },\n {\n me: account,\n node,\n done: () => {\n node.gracefulShutdown();\n },\n logOut: async () => {\n await storage.clear();\n node.gracefulShutdown();\n },\n },\n {\n credentials,\n },\n );\n\n return context;\n }\n\n static fromGuest<Acc extends Account>(\n { guest }: { guest: AnonymousJazzAgent },\n props: TestJazzContextManagerProps<Acc> = {},\n ) {\n const context = new TestJazzContextManager<Acc>();\n const node = guest.node;\n\n context.updateContext(props, {\n guest,\n node,\n done: () => {\n node.gracefulShutdown();\n },\n logOut: async () => {\n node.gracefulShutdown();\n },\n });\n\n return context;\n }\n\n async createContext(\n props: TestJazzContextManagerProps<Acc>,\n authProps?: JazzContextManagerAuthProps,\n ) {\n this.props = props;\n\n if (!syncServer.current) {\n throw new Error(\n \"You need to setup a test sync server with setupJazzTestSync to use the Auth functions\",\n );\n }\n\n const context = await createJazzContext<Acc>({\n credentials: authProps?.credentials,\n defaultProfileName: props.defaultProfileName,\n newAccountProps: authProps?.newAccountProps,\n peersToLoadFrom: [getPeerConnectedToTestSyncServer()],\n crypto: await TestJSCrypto.create(),\n sessionProvider: randomSessionProvider,\n authSecretStorage: this.getAuthSecretStorage(),\n AccountSchema: props.AccountSchema,\n });\n\n await this.updateContext(\n props,\n {\n me: context.account,\n node: context.node,\n done: () => {\n context.done();\n },\n logOut: () => {\n return context.logOut();\n },\n },\n authProps,\n );\n }\n}\n\nexport function linkAccounts(\n a: Account,\n b: Account,\n aRole: \"server\" | \"client\" = \"server\",\n bRole: \"server\" | \"client\" = \"server\",\n) {\n const [aPeer, bPeer] = cojsonInternals.connectedPeers(b.id, a.id, {\n peer1role: aRole,\n peer2role: bRole,\n });\n\n a._raw.core.node.syncManager.addPeer(aPeer);\n b._raw.core.node.syncManager.addPeer(bPeer);\n}\n\nexport async function setupJazzTestSync() {\n if (syncServer.current) {\n syncServer.current.gracefulShutdown();\n }\n\n const account = await Account.create({\n creationProps: {\n name: \"Test Account\",\n },\n crypto: await TestJSCrypto.create(),\n });\n\n syncServer.current = account._raw.core.node;\n\n return account;\n}\n"],"mappings":"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","names":["account"]}
|
package/package.json
CHANGED
@@ -16,6 +16,7 @@ export type AuthSetPayload = {
|
|
16
16
|
export class AuthSecretStorage {
|
17
17
|
private listeners: Set<(isAuthenticated: boolean) => void>;
|
18
18
|
public isAuthenticated: boolean;
|
19
|
+
notify = false;
|
19
20
|
|
20
21
|
constructor() {
|
21
22
|
this.listeners = new Set();
|
@@ -109,7 +110,10 @@ export class AuthSecretStorage {
|
|
109
110
|
provider: payload.provider,
|
110
111
|
}),
|
111
112
|
);
|
112
|
-
|
113
|
+
|
114
|
+
if (this.notify) {
|
115
|
+
this.emitUpdate(payload);
|
116
|
+
}
|
113
117
|
}
|
114
118
|
|
115
119
|
getIsAuthenticated(data: AuthCredentials | null): boolean {
|
@@ -138,6 +142,9 @@ export class AuthSecretStorage {
|
|
138
142
|
async clear() {
|
139
143
|
const kvStore = KvStoreContext.getInstance().getStorage();
|
140
144
|
await kvStore.delete(STORAGE_KEY);
|
141
|
-
|
145
|
+
|
146
|
+
if (this.notify) {
|
147
|
+
this.emitUpdate(null);
|
148
|
+
}
|
142
149
|
}
|
143
150
|
}
|
@@ -14,7 +14,7 @@ export type JazzContextManagerAuthProps = {
|
|
14
14
|
|
15
15
|
export type JazzContextManagerBaseProps<Acc extends Account> = {
|
16
16
|
onAnonymousAccountDiscarded?: (anonymousAccount: Acc) => Promise<void>;
|
17
|
-
onLogOut?: () => void
|
17
|
+
onLogOut?: () => void | Promise<unknown>;
|
18
18
|
};
|
19
19
|
|
20
20
|
type PlatformSpecificAuthContext<Acc extends Account> = {
|
@@ -43,6 +43,10 @@ export class JazzContextManager<
|
|
43
43
|
protected context: PlatformSpecificContext<Acc> | undefined;
|
44
44
|
protected props: P | undefined;
|
45
45
|
protected authSecretStorage = new AuthSecretStorage();
|
46
|
+
protected authSecretStorageWithNotify = Object.assign(
|
47
|
+
Object.create(this.authSecretStorage),
|
48
|
+
{ notify: true },
|
49
|
+
);
|
46
50
|
protected authenticating = false;
|
47
51
|
|
48
52
|
constructor() {
|
@@ -59,7 +63,11 @@ export class JazzContextManager<
|
|
59
63
|
throw new Error("Not implemented");
|
60
64
|
}
|
61
65
|
|
62
|
-
updateContext(
|
66
|
+
async updateContext(
|
67
|
+
props: P,
|
68
|
+
context: PlatformSpecificContext<Acc>,
|
69
|
+
authProps?: JazzContextManagerAuthProps,
|
70
|
+
) {
|
63
71
|
// When authenticating we don't want to close the previous context
|
64
72
|
// because we might need to handle the onAnonymousAccountDiscarded callback
|
65
73
|
if (!this.authenticating) {
|
@@ -75,6 +83,12 @@ export class JazzContextManager<
|
|
75
83
|
logOut: this.logOut,
|
76
84
|
};
|
77
85
|
|
86
|
+
if (authProps?.credentials) {
|
87
|
+
this.authSecretStorage.emitUpdate(authProps.credentials);
|
88
|
+
} else {
|
89
|
+
this.authSecretStorage.emitUpdate(await this.authSecretStorage.get());
|
90
|
+
}
|
91
|
+
|
78
92
|
this.notify();
|
79
93
|
}
|
80
94
|
|
@@ -88,7 +102,9 @@ export class JazzContextManager<
|
|
88
102
|
}
|
89
103
|
|
90
104
|
getAuthSecretStorage() {
|
91
|
-
|
105
|
+
// External updates of the auth secret storage are notified by default (e.g. when registering a new Auth provider)
|
106
|
+
// We skip internal notify to ensure that the isAuthenticated changes are notified along with the context updates
|
107
|
+
return this.authSecretStorageWithNotify;
|
92
108
|
}
|
93
109
|
|
94
110
|
logOut = async () => {
|
@@ -96,8 +112,8 @@ export class JazzContextManager<
|
|
96
112
|
return;
|
97
113
|
}
|
98
114
|
|
115
|
+
await this.props.onLogOut?.();
|
99
116
|
await this.context.logOut();
|
100
|
-
this.props.onLogOut?.();
|
101
117
|
return this.createContext(this.props);
|
102
118
|
};
|
103
119
|
|
@@ -109,6 +125,9 @@ export class JazzContextManager<
|
|
109
125
|
this.context.done();
|
110
126
|
};
|
111
127
|
|
128
|
+
/**
|
129
|
+
* Authenticates the user with the given credentials
|
130
|
+
*/
|
112
131
|
authenticate = async (credentials: AuthCredentials) => {
|
113
132
|
if (!this.props) {
|
114
133
|
throw new Error("Props required");
|
@@ -222,9 +222,6 @@ export async function createJazzContext<Acc extends Account>(options: {
|
|
222
222
|
authSecretStorage.clear();
|
223
223
|
},
|
224
224
|
});
|
225
|
-
|
226
|
-
// To align the isAuthenticated state with the credentials
|
227
|
-
authSecretStorage.emitUpdate(credentials);
|
228
225
|
} else {
|
229
226
|
const secretSeed = options.crypto.newRandomSecretSeed();
|
230
227
|
|
package/src/testing.ts
CHANGED
@@ -4,6 +4,7 @@ import { PureJSCrypto } from "cojson/dist/crypto/PureJSCrypto";
|
|
4
4
|
import {
|
5
5
|
Account,
|
6
6
|
AccountClass,
|
7
|
+
AuthCredentials,
|
7
8
|
JazzContextManagerAuthProps,
|
8
9
|
} from "./exports.js";
|
9
10
|
import {
|
@@ -182,13 +183,14 @@ export class TestJazzContextManager<
|
|
182
183
|
const storage = context.getAuthSecretStorage();
|
183
184
|
const node = account._raw.core.node;
|
184
185
|
|
185
|
-
|
186
|
+
const credentials = {
|
186
187
|
accountID: account.id,
|
187
188
|
accountSecret: node.account.agentSecret,
|
188
189
|
secretSeed: SecretSeedMap.get(account.id),
|
189
190
|
provider,
|
190
|
-
}
|
191
|
-
|
191
|
+
} satisfies AuthCredentials;
|
192
|
+
|
193
|
+
storage.set(credentials);
|
192
194
|
|
193
195
|
context.updateContext(
|
194
196
|
{
|
@@ -202,9 +204,13 @@ export class TestJazzContextManager<
|
|
202
204
|
node.gracefulShutdown();
|
203
205
|
},
|
204
206
|
logOut: async () => {
|
207
|
+
await storage.clear();
|
205
208
|
node.gracefulShutdown();
|
206
209
|
},
|
207
210
|
},
|
211
|
+
{
|
212
|
+
credentials,
|
213
|
+
},
|
208
214
|
);
|
209
215
|
|
210
216
|
return context;
|
@@ -254,16 +260,20 @@ export class TestJazzContextManager<
|
|
254
260
|
AccountSchema: props.AccountSchema,
|
255
261
|
});
|
256
262
|
|
257
|
-
this.updateContext(
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
context.
|
262
|
-
|
263
|
-
|
264
|
-
|
263
|
+
await this.updateContext(
|
264
|
+
props,
|
265
|
+
{
|
266
|
+
me: context.account,
|
267
|
+
node: context.node,
|
268
|
+
done: () => {
|
269
|
+
context.done();
|
270
|
+
},
|
271
|
+
logOut: () => {
|
272
|
+
return context.logOut();
|
273
|
+
},
|
265
274
|
},
|
266
|
-
|
275
|
+
authProps,
|
276
|
+
);
|
267
277
|
}
|
268
278
|
}
|
269
279
|
|
@@ -13,12 +13,12 @@ KvStoreContext.getInstance().initialize(kvStore);
|
|
13
13
|
let authSecretStorage = new AuthSecretStorage();
|
14
14
|
|
15
15
|
describe("AuthSecretStorage", () => {
|
16
|
-
beforeEach(() => {
|
17
|
-
kvStore.clearAll();
|
18
|
-
authSecretStorage = new AuthSecretStorage();
|
19
|
-
});
|
20
|
-
|
21
16
|
describe("migrate", () => {
|
17
|
+
beforeEach(() => {
|
18
|
+
kvStore.clearAll();
|
19
|
+
authSecretStorage = new AuthSecretStorage();
|
20
|
+
});
|
21
|
+
|
22
22
|
it("should migrate demo auth secret", async () => {
|
23
23
|
const demoSecret = JSON.stringify({
|
24
24
|
accountID: "demo123",
|
@@ -79,6 +79,11 @@ describe("AuthSecretStorage", () => {
|
|
79
79
|
});
|
80
80
|
|
81
81
|
describe("get", () => {
|
82
|
+
beforeEach(() => {
|
83
|
+
kvStore.clearAll();
|
84
|
+
authSecretStorage = new AuthSecretStorage();
|
85
|
+
});
|
86
|
+
|
82
87
|
it("should return null when no data exists", async () => {
|
83
88
|
expect(await authSecretStorage.get()).toBeNull();
|
84
89
|
});
|
@@ -132,6 +137,11 @@ describe("AuthSecretStorage", () => {
|
|
132
137
|
});
|
133
138
|
|
134
139
|
describe("set", () => {
|
140
|
+
beforeEach(() => {
|
141
|
+
kvStore.clearAll();
|
142
|
+
authSecretStorage = new AuthSecretStorage();
|
143
|
+
});
|
144
|
+
|
135
145
|
it("should set credentials with secretSeed", async () => {
|
136
146
|
const payload = {
|
137
147
|
accountID: "test123" as ID<Account>,
|
@@ -165,61 +175,14 @@ describe("AuthSecretStorage", () => {
|
|
165
175
|
const stored = JSON.parse((await kvStore.get("jazz-logged-in-secret"))!);
|
166
176
|
expect(stored).toEqual(payload);
|
167
177
|
});
|
168
|
-
|
169
|
-
it("should emit update event when setting credentials", async () => {
|
170
|
-
const handler = vi.fn();
|
171
|
-
authSecretStorage.onUpdate(handler);
|
172
|
-
|
173
|
-
await authSecretStorage.set({
|
174
|
-
accountID: "test123" as ID<Account>,
|
175
|
-
accountSecret:
|
176
|
-
"secret123" as `sealerSecret_z${string}/signerSecret_z${string}`,
|
177
|
-
provider: "passphrase",
|
178
|
-
});
|
179
|
-
|
180
|
-
expect(handler).toHaveBeenCalled();
|
181
|
-
});
|
182
178
|
});
|
183
179
|
|
184
|
-
describe("
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
it("should return false for anonymous credentials", async () => {
|
190
|
-
await authSecretStorage.set({
|
191
|
-
accountID: "test123" as ID<Account>,
|
192
|
-
accountSecret:
|
193
|
-
"secret123" as `sealerSecret_z${string}/signerSecret_z${string}`,
|
194
|
-
secretSeed: new Uint8Array([1, 2, 3]),
|
195
|
-
provider: "anonymous",
|
196
|
-
});
|
197
|
-
expect(authSecretStorage.isAuthenticated).toBe(false);
|
198
|
-
});
|
199
|
-
|
200
|
-
it("should return true for non-anonymous credentials", async () => {
|
201
|
-
await authSecretStorage.set({
|
202
|
-
accountID: "test123" as ID<Account>,
|
203
|
-
accountSecret:
|
204
|
-
"secret123" as `sealerSecret_z${string}/signerSecret_z${string}`,
|
205
|
-
secretSeed: new Uint8Array([1, 2, 3]),
|
206
|
-
provider: "demo",
|
207
|
-
});
|
208
|
-
expect(authSecretStorage.isAuthenticated).toBe(true);
|
209
|
-
});
|
210
|
-
|
211
|
-
it("should return true when the provider is missing", async () => {
|
212
|
-
await authSecretStorage.set({
|
213
|
-
accountID: "test123" as ID<Account>,
|
214
|
-
accountSecret:
|
215
|
-
"secret123" as `sealerSecret_z${string}/signerSecret_z${string}`,
|
216
|
-
secretSeed: new Uint8Array([1, 2, 3]),
|
217
|
-
} as any);
|
218
|
-
expect(authSecretStorage.isAuthenticated).toBe(true);
|
180
|
+
describe("onUpdate", () => {
|
181
|
+
beforeEach(() => {
|
182
|
+
kvStore.clearAll();
|
183
|
+
authSecretStorage = new AuthSecretStorage();
|
219
184
|
});
|
220
|
-
});
|
221
185
|
|
222
|
-
describe("onUpdate", () => {
|
223
186
|
it("should add and remove event listener", () => {
|
224
187
|
const handler = vi.fn();
|
225
188
|
|
@@ -275,6 +238,11 @@ describe("AuthSecretStorage", () => {
|
|
275
238
|
});
|
276
239
|
|
277
240
|
describe("clear", () => {
|
241
|
+
beforeEach(() => {
|
242
|
+
kvStore.clearAll();
|
243
|
+
authSecretStorage = new AuthSecretStorage();
|
244
|
+
});
|
245
|
+
|
278
246
|
it("should remove stored credentials", async () => {
|
279
247
|
await authSecretStorage.set({
|
280
248
|
accountID: "test123" as ID<Account>,
|
@@ -287,21 +255,179 @@ describe("AuthSecretStorage", () => {
|
|
287
255
|
|
288
256
|
expect(await authSecretStorage.get()).toBeNull();
|
289
257
|
});
|
258
|
+
});
|
290
259
|
|
291
|
-
|
292
|
-
|
293
|
-
|
294
|
-
|
295
|
-
|
296
|
-
|
260
|
+
describe("notify=true", () => {
|
261
|
+
beforeEach(() => {
|
262
|
+
kvStore.clearAll();
|
263
|
+
authSecretStorage = new AuthSecretStorage();
|
264
|
+
authSecretStorage.notify = true;
|
265
|
+
});
|
266
|
+
|
267
|
+
describe("set", () => {
|
268
|
+
it("should emit update event when setting credentials", async () => {
|
269
|
+
const handler = vi.fn();
|
270
|
+
authSecretStorage.onUpdate(handler);
|
271
|
+
|
272
|
+
await authSecretStorage.set({
|
273
|
+
accountID: "test123" as ID<Account>,
|
274
|
+
accountSecret:
|
275
|
+
"secret123" as `sealerSecret_z${string}/signerSecret_z${string}`,
|
276
|
+
provider: "passphrase",
|
277
|
+
});
|
278
|
+
|
279
|
+
expect(handler).toHaveBeenCalled();
|
297
280
|
});
|
281
|
+
});
|
298
282
|
|
299
|
-
|
300
|
-
|
283
|
+
describe("isAuthenticated", () => {
|
284
|
+
it("should return false when no data exists", async () => {
|
285
|
+
expect(authSecretStorage.isAuthenticated).toBe(false);
|
286
|
+
});
|
301
287
|
|
302
|
-
|
288
|
+
it("should return false for anonymous credentials", async () => {
|
289
|
+
await authSecretStorage.set({
|
290
|
+
accountID: "test123" as ID<Account>,
|
291
|
+
accountSecret:
|
292
|
+
"secret123" as `sealerSecret_z${string}/signerSecret_z${string}`,
|
293
|
+
secretSeed: new Uint8Array([1, 2, 3]),
|
294
|
+
provider: "anonymous",
|
295
|
+
});
|
296
|
+
expect(authSecretStorage.isAuthenticated).toBe(false);
|
297
|
+
});
|
298
|
+
|
299
|
+
it("should return true for non-anonymous credentials", async () => {
|
300
|
+
await authSecretStorage.set({
|
301
|
+
accountID: "test123" as ID<Account>,
|
302
|
+
accountSecret:
|
303
|
+
"secret123" as `sealerSecret_z${string}/signerSecret_z${string}`,
|
304
|
+
secretSeed: new Uint8Array([1, 2, 3]),
|
305
|
+
provider: "demo",
|
306
|
+
});
|
307
|
+
expect(authSecretStorage.isAuthenticated).toBe(true);
|
308
|
+
});
|
309
|
+
|
310
|
+
it("should return true when the provider is missing", async () => {
|
311
|
+
await authSecretStorage.set({
|
312
|
+
accountID: "test123" as ID<Account>,
|
313
|
+
accountSecret:
|
314
|
+
"secret123" as `sealerSecret_z${string}/signerSecret_z${string}`,
|
315
|
+
secretSeed: new Uint8Array([1, 2, 3]),
|
316
|
+
} as any);
|
317
|
+
expect(authSecretStorage.isAuthenticated).toBe(true);
|
318
|
+
});
|
319
|
+
});
|
320
|
+
|
321
|
+
describe("clear", () => {
|
322
|
+
it("should emit update event when clearing", async () => {
|
323
|
+
await authSecretStorage.set({
|
324
|
+
accountID: "test123" as ID<Account>,
|
325
|
+
accountSecret:
|
326
|
+
"secret123" as `sealerSecret_z${string}/signerSecret_z${string}`,
|
327
|
+
provider: "passphrase",
|
328
|
+
});
|
329
|
+
|
330
|
+
const handler = vi.fn();
|
331
|
+
authSecretStorage.onUpdate(handler);
|
332
|
+
|
333
|
+
await authSecretStorage.clear();
|
334
|
+
|
335
|
+
expect(handler).toHaveBeenCalled();
|
336
|
+
});
|
337
|
+
});
|
338
|
+
});
|
339
|
+
|
340
|
+
describe("notify=false", () => {
|
341
|
+
beforeEach(() => {
|
342
|
+
kvStore.clearAll();
|
343
|
+
authSecretStorage = new AuthSecretStorage();
|
344
|
+
});
|
345
|
+
|
346
|
+
describe("set", () => {
|
347
|
+
it("should not emit update event when setting credentials", async () => {
|
348
|
+
const handler = vi.fn();
|
349
|
+
authSecretStorage.onUpdate(handler);
|
350
|
+
|
351
|
+
await authSecretStorage.set({
|
352
|
+
accountID: "test123" as ID<Account>,
|
353
|
+
accountSecret:
|
354
|
+
"secret123" as `sealerSecret_z${string}/signerSecret_z${string}`,
|
355
|
+
provider: "passphrase",
|
356
|
+
});
|
303
357
|
|
304
|
-
|
358
|
+
expect(handler).not.toHaveBeenCalled();
|
359
|
+
});
|
360
|
+
});
|
361
|
+
|
362
|
+
describe("isAuthenticated", () => {
|
363
|
+
it("should return false when no data exists", async () => {
|
364
|
+
expect(authSecretStorage.isAuthenticated).toBe(false);
|
365
|
+
});
|
366
|
+
|
367
|
+
it("should return false for anonymous credentials", async () => {
|
368
|
+
await authSecretStorage.set({
|
369
|
+
accountID: "test123" as ID<Account>,
|
370
|
+
accountSecret:
|
371
|
+
"secret123" as `sealerSecret_z${string}/signerSecret_z${string}`,
|
372
|
+
secretSeed: new Uint8Array([1, 2, 3]),
|
373
|
+
provider: "anonymous",
|
374
|
+
});
|
375
|
+
expect(authSecretStorage.isAuthenticated).toBe(false);
|
376
|
+
});
|
377
|
+
|
378
|
+
it("should return true for non-anonymous credentials", async () => {
|
379
|
+
await authSecretStorage.set({
|
380
|
+
accountID: "test123" as ID<Account>,
|
381
|
+
accountSecret:
|
382
|
+
"secret123" as `sealerSecret_z${string}/signerSecret_z${string}`,
|
383
|
+
secretSeed: new Uint8Array([1, 2, 3]),
|
384
|
+
provider: "demo",
|
385
|
+
});
|
386
|
+
expect(authSecretStorage.isAuthenticated).toBe(false);
|
387
|
+
authSecretStorage.emitUpdate({
|
388
|
+
accountID: "test123" as ID<Account>,
|
389
|
+
accountSecret:
|
390
|
+
"secret123" as `sealerSecret_z${string}/signerSecret_z${string}`,
|
391
|
+
secretSeed: new Uint8Array([1, 2, 3]),
|
392
|
+
provider: "demo",
|
393
|
+
});
|
394
|
+
expect(authSecretStorage.isAuthenticated).toBe(true);
|
395
|
+
});
|
396
|
+
|
397
|
+
it("should return true when the provider is missing", async () => {
|
398
|
+
await authSecretStorage.set({
|
399
|
+
accountID: "test123" as ID<Account>,
|
400
|
+
accountSecret:
|
401
|
+
"secret123" as `sealerSecret_z${string}/signerSecret_z${string}`,
|
402
|
+
secretSeed: new Uint8Array([1, 2, 3]),
|
403
|
+
} as any);
|
404
|
+
expect(authSecretStorage.isAuthenticated).toBe(false);
|
405
|
+
authSecretStorage.emitUpdate({
|
406
|
+
accountID: "test123" as ID<Account>,
|
407
|
+
accountSecret:
|
408
|
+
"secret123" as `sealerSecret_z${string}/signerSecret_z${string}`,
|
409
|
+
secretSeed: new Uint8Array([1, 2, 3]),
|
410
|
+
} as any);
|
411
|
+
expect(authSecretStorage.isAuthenticated).toBe(true);
|
412
|
+
});
|
413
|
+
});
|
414
|
+
|
415
|
+
describe("clear", () => {
|
416
|
+
it("should not emit update event when clearing", async () => {
|
417
|
+
await authSecretStorage.set({
|
418
|
+
accountID: "test123" as ID<Account>,
|
419
|
+
accountSecret:
|
420
|
+
"secret123" as `sealerSecret_z${string}/signerSecret_z${string}`,
|
421
|
+
provider: "passphrase",
|
422
|
+
});
|
423
|
+
|
424
|
+
const handler = vi.fn();
|
425
|
+
authSecretStorage.onUpdate(handler);
|
426
|
+
|
427
|
+
await authSecretStorage.clear();
|
428
|
+
|
429
|
+
expect(handler).not.toHaveBeenCalled();
|
430
|
+
});
|
305
431
|
});
|
306
432
|
});
|
307
433
|
});
|