@novasamatech/host-papp 0.5.0-0 → 0.5.0-10
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/.papi/descriptors/dist/common-types.d.ts +8667 -0
- package/.papi/descriptors/dist/common.d.ts +1 -0
- package/.papi/descriptors/dist/descriptors-UUEW32EL.mjs +27 -0
- package/.papi/descriptors/dist/descriptors.d.ts +1 -0
- package/.papi/descriptors/dist/index.d.ts +10 -0
- package/.papi/descriptors/dist/index.js +237 -0
- package/.papi/descriptors/dist/index.mjs +148 -0
- package/.papi/descriptors/dist/metadataTypes-E4AQJDJR.mjs +6 -0
- package/.papi/descriptors/dist/metadataTypes.d.ts +2 -0
- package/.papi/descriptors/dist/people_lite.d.ts +7757 -0
- package/.papi/descriptors/dist/people_lite_metadata-EIVHV27X.mjs +6 -0
- package/.papi/descriptors/dist/people_lite_metadata.d.ts +2 -0
- package/.papi/descriptors/package.json +24 -0
- package/.papi/metadata/people_lite.scale +0 -0
- package/.papi/polkadot-api.json +15 -0
- package/dist/adapters/identity/rpc.d.ts +6 -4
- package/dist/adapters/identity/rpc.js +96 -26
- package/dist/adapters/identity/types.d.ts +3 -1
- package/dist/adapters/lazyClient/papi.js +5 -0
- package/dist/adapters/lazyClient/types.d.ts +1 -0
- package/dist/adapters/statement/rpc.js +58 -10
- package/dist/adapters/statement/types.d.ts +6 -3
- package/dist/adapters/storage/localStorage.js +26 -4
- package/dist/adapters/storage/memory.js +14 -4
- package/dist/adapters/storage/types.d.ts +5 -2
- package/dist/adapters/storage/types.js +1 -1
- package/dist/components/auth/codec.d.ts +9 -0
- package/dist/components/auth/codec.js +10 -0
- package/dist/components/auth/codecs.d.ts +9 -0
- package/dist/components/auth/codecs.js +10 -0
- package/dist/components/auth/index.d.ts +36 -0
- package/dist/components/auth/index.js +150 -0
- package/dist/components/auth/types.d.ts +15 -0
- package/dist/components/auth/types.js +1 -0
- package/dist/components/session.d.ts +34 -0
- package/dist/components/session.js +54 -0
- package/dist/components/sso/index.d.ts +36 -0
- package/dist/components/sso/index.js +150 -0
- package/dist/components/sso/scale/handshake.d.ts +9 -0
- package/dist/components/sso/scale/handshake.js +10 -0
- package/dist/components/sso/types.d.ts +15 -0
- package/dist/components/sso/types.js +1 -0
- package/dist/components/transport.d.ts +27 -0
- package/dist/components/transport.js +57 -0
- package/dist/components/user/codec.d.ts +16 -0
- package/dist/components/user/codec.js +13 -0
- package/dist/components/user/index.d.ts +22 -0
- package/dist/components/user/index.js +58 -0
- package/dist/components/user/ssoMessageStream.d.ts +10 -0
- package/dist/components/user/ssoMessageStream.js +8 -0
- package/dist/components/user/ssoSession.d.ts +5 -0
- package/dist/components/user/ssoSession.js +5 -0
- package/dist/components/user/storage.d.ts +27 -0
- package/dist/components/user/storage.js +143 -0
- package/dist/components/user/types.d.ts +6 -0
- package/dist/components/user/types.js +1 -0
- package/dist/components/user/userSessionStorage.d.ts +20 -0
- package/dist/components/user/userSessionStorage.js +24 -0
- package/dist/components/user.d.ts +74 -0
- package/dist/components/user.js +188 -0
- package/dist/constants.d.ts +2 -1
- package/dist/constants.js +5 -1
- package/dist/crypto.d.ts +29 -0
- package/dist/crypto.js +86 -0
- package/dist/helpers/abortError.d.ts +4 -0
- package/dist/helpers/abortError.js +8 -0
- package/dist/helpers/callbackRaceResolver.d.ts +1 -0
- package/dist/helpers/callbackRaceResolver.js +17 -0
- package/dist/helpers/result.d.ts +12 -0
- package/dist/helpers/result.js +15 -0
- package/dist/helpers/result.spec.d.ts +1 -0
- package/dist/helpers/result.spec.js +23 -0
- package/dist/helpers/state.d.ts +16 -0
- package/dist/helpers/state.js +51 -0
- package/dist/helpers/utils.d.ts +2 -1
- package/dist/helpers/utils.js +11 -2
- package/dist/helpers/zipWith.d.ts +4 -0
- package/dist/helpers/zipWith.js +11 -0
- package/dist/identity/impl.d.ts +6 -0
- package/dist/identity/impl.js +68 -0
- package/dist/identity/rpcAdapter.d.ts +3 -0
- package/dist/identity/rpcAdapter.js +46 -0
- package/dist/identity/types.d.ts +21 -0
- package/dist/identity/types.js +1 -0
- package/dist/index.d.ts +7 -3
- package/dist/index.js +2 -7
- package/dist/modules/crypto.d.ts +8 -9
- package/dist/modules/crypto.js +20 -42
- package/dist/modules/secretStorage.d.ts +13 -12
- package/dist/modules/secretStorage.js +34 -43
- package/dist/modules/session/helpers.d.ts +5 -0
- package/dist/modules/session/helpers.js +29 -0
- package/dist/modules/session/session.d.ts +12 -0
- package/dist/modules/session/session.js +50 -0
- package/dist/modules/session/types.d.ts +12 -0
- package/dist/modules/session/types.js +1 -0
- package/dist/modules/signIn.d.ts +32 -11
- package/dist/modules/signIn.js +98 -101
- package/dist/modules/state.d.ts +16 -0
- package/dist/modules/state.js +50 -0
- package/dist/modules/statementStore.d.ts +10 -11
- package/dist/modules/statementStore.js +16 -14
- package/dist/modules/statementTopic.d.ts +34 -0
- package/dist/modules/statementTopic.js +46 -0
- package/dist/modules/storageView.d.ts +25 -0
- package/dist/modules/storageView.js +51 -0
- package/dist/modules/syncStorage.d.ts +25 -0
- package/dist/modules/syncStorage.js +76 -0
- package/dist/modules/transport/codec.d.ts +24 -0
- package/dist/modules/transport/codec.js +36 -0
- package/dist/modules/transport/crypto.d.ts +2 -0
- package/dist/modules/transport/crypto.js +20 -0
- package/dist/modules/transport/transport.d.ts +42 -0
- package/dist/modules/transport/transport.js +66 -0
- package/dist/modules/user.d.ts +67 -0
- package/dist/modules/user.js +188 -0
- package/dist/modules/userManager.d.ts +15 -0
- package/dist/modules/userManager.js +105 -0
- package/dist/modules/userStorage.d.ts +19 -0
- package/dist/modules/userStorage.js +108 -0
- package/dist/modules/userStore.d.ts +15 -0
- package/dist/modules/userStore.js +105 -0
- package/dist/papp.d.ts +25 -13
- package/dist/papp.js +19 -50
- package/dist/sso/auth/attestationService.d.ts +18 -0
- package/dist/sso/auth/attestationService.js +171 -0
- package/dist/sso/auth/impl.d.ts +53 -0
- package/dist/sso/auth/impl.js +161 -0
- package/dist/sso/auth/scale/handshake.d.ts +9 -0
- package/dist/sso/auth/scale/handshake.js +10 -0
- package/dist/sso/auth/types.d.ts +17 -0
- package/dist/sso/auth/types.js +1 -0
- package/dist/sso/session/impl.d.ts +23 -0
- package/dist/sso/session/impl.js +57 -0
- package/dist/sso/session/scale/remoteMessage.d.ts +10 -0
- package/dist/sso/session/scale/remoteMessage.js +13 -0
- package/dist/sso/session/sessionManager.d.ts +23 -0
- package/dist/sso/session/sessionManager.js +58 -0
- package/dist/sso/session/ssoSession.d.ts +8 -0
- package/dist/sso/session/ssoSession.js +5 -0
- package/dist/sso/session/ssoSessionStorage.d.ts +21 -0
- package/dist/sso/session/ssoSessionStorage.js +20 -0
- package/dist/sso/session/types.d.ts +6 -0
- package/dist/sso/session/types.js +1 -0
- package/dist/sso/session/userSessionStorage.d.ts +21 -0
- package/dist/sso/session/userSessionStorage.js +20 -0
- package/dist/sso/sessionManager/attestationService.d.ts +5 -0
- package/dist/sso/sessionManager/attestationService.js +15 -0
- package/dist/sso/sessionManager/impl.d.ts +22 -0
- package/dist/sso/sessionManager/impl.js +71 -0
- package/dist/sso/sessionManager/repository/ssoSessionRepository.d.ts +22 -0
- package/dist/sso/sessionManager/repository/ssoSessionRepository.js +27 -0
- package/dist/sso/sessionManager/scale/hex.d.ts +1 -0
- package/dist/sso/sessionManager/scale/hex.js +3 -0
- package/dist/sso/sessionManager/scale/remoteMessage.d.ts +41 -0
- package/dist/sso/sessionManager/scale/remoteMessage.js +13 -0
- package/dist/sso/sessionManager/scale/signPayloadRequest.d.ts +19 -0
- package/dist/sso/sessionManager/scale/signPayloadRequest.js +19 -0
- package/dist/sso/sessionManager/scale/signPayloadResponse.d.ts +12 -0
- package/dist/sso/sessionManager/scale/signPayloadResponse.js +9 -0
- package/dist/sso/sessionManager/scale/signRequest.d.ts +19 -0
- package/dist/sso/sessionManager/scale/signRequest.js +19 -0
- package/dist/sso/sessionManager/scale/signResponse.d.ts +6 -0
- package/dist/sso/sessionManager/scale/signResponse.js +5 -0
- package/dist/sso/sessionManager/ssoSession.d.ts +23 -0
- package/dist/sso/sessionManager/ssoSession.js +69 -0
- package/dist/sso/sessionManager/ssoSessionProver.d.ts +4 -0
- package/dist/sso/sessionManager/ssoSessionProver.js +35 -0
- package/dist/sso/sessionManager/types.d.ts +6 -0
- package/dist/sso/sessionManager/types.js +1 -0
- package/dist/sso/sessionManager/userSession.d.ts +22 -0
- package/dist/sso/sessionManager/userSession.js +106 -0
- package/dist/sso/ssoSessionProver.d.ts +4 -0
- package/dist/sso/ssoSessionProver.js +35 -0
- package/dist/sso/ssoSessionRepository.d.ts +18 -0
- package/dist/sso/ssoSessionRepository.js +27 -0
- package/dist/sso/userSecretRepository.d.ts +17 -0
- package/dist/sso/userSecretRepository.js +45 -0
- package/dist/sso/userSessionRepository.d.ts +18 -0
- package/dist/sso/userSessionRepository.js +26 -0
- package/dist/structs.d.ts +10 -10
- package/dist/structs.js +17 -13
- package/dist/types.d.ts +1 -1
- package/package.json +14 -7
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { createEncryption } from '@novasamatech/statement-store';
|
|
2
|
+
import { okAsync } from 'neverthrow';
|
|
3
|
+
import { createState } from '../../helpers/state.js';
|
|
4
|
+
import { createSsoStatementProver } from '../ssoSessionProver.js';
|
|
5
|
+
import { createUserSession } from './userSession.js';
|
|
6
|
+
export function createSsoSessionManager({ ssoSessionRepository, userSecretRepository, statementStore, storage, }) {
|
|
7
|
+
const localSessions = createState({});
|
|
8
|
+
const disconnect = (session) => {
|
|
9
|
+
return ssoSessionRepository.filter(s => s.id !== session.id).map(() => undefined);
|
|
10
|
+
};
|
|
11
|
+
ssoSessionRepository.subscribe(userSessions => {
|
|
12
|
+
const activeSessions = localSessions.read();
|
|
13
|
+
const toRemove = new Set(Object.keys(activeSessions));
|
|
14
|
+
const toAdd = new Set();
|
|
15
|
+
for (const userSession of userSessions) {
|
|
16
|
+
if (userSession.id in activeSessions)
|
|
17
|
+
continue;
|
|
18
|
+
const session = createSession(userSession, statementStore, storage, userSecretRepository);
|
|
19
|
+
toRemove.delete(userSession.id);
|
|
20
|
+
toAdd.add(session);
|
|
21
|
+
session.subscribe(message => {
|
|
22
|
+
switch (message.data.tag) {
|
|
23
|
+
case 'v1': {
|
|
24
|
+
switch (message.data.value.tag) {
|
|
25
|
+
case 'Disconnected':
|
|
26
|
+
return disconnect(userSession).map(() => true);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
return okAsync(false);
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
if (toRemove.size > 0) {
|
|
34
|
+
localSessions.write(prev => {
|
|
35
|
+
return Object.fromEntries(Object.entries(prev).filter(([id]) => !toRemove.has(id)));
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
if (toAdd.size > 0) {
|
|
39
|
+
localSessions.write(prev => ({
|
|
40
|
+
...prev,
|
|
41
|
+
...Object.fromEntries(Array.from(toAdd).map(s => [s.id, s])),
|
|
42
|
+
}));
|
|
43
|
+
}
|
|
44
|
+
});
|
|
45
|
+
return {
|
|
46
|
+
sessions: {
|
|
47
|
+
read: () => Object.values(localSessions.read()),
|
|
48
|
+
subscribe: (callback) => localSessions.subscribe(sessions => callback(Object.values(sessions))),
|
|
49
|
+
},
|
|
50
|
+
disconnect(userSession) {
|
|
51
|
+
const session = createSession(userSession, statementStore, storage, userSecretRepository);
|
|
52
|
+
return session.sendDisconnectMessage().andThen(() => disconnect(userSession));
|
|
53
|
+
},
|
|
54
|
+
dispose() {
|
|
55
|
+
for (const session of Object.values(localSessions.read())) {
|
|
56
|
+
session.dispose();
|
|
57
|
+
}
|
|
58
|
+
},
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
function createSession(userSession, statementStore, storage, userSecretRepository) {
|
|
62
|
+
const encryption = createEncryption(userSession.remoteAccount.publicKey);
|
|
63
|
+
const prover = createSsoStatementProver(userSession, userSecretRepository);
|
|
64
|
+
return createUserSession({
|
|
65
|
+
userSession,
|
|
66
|
+
statementStore,
|
|
67
|
+
encryption,
|
|
68
|
+
storage,
|
|
69
|
+
prover,
|
|
70
|
+
});
|
|
71
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { LocalSessionAccount, RemoteSessionAccount } from '@novasamatech/statement-store';
|
|
2
|
+
import type { StorageAdapter } from '@novasamatech/storage-adapter';
|
|
3
|
+
export type SsoSessionRepository = ReturnType<typeof createSsoSessionRepository>;
|
|
4
|
+
export type UserSession = {
|
|
5
|
+
id: string;
|
|
6
|
+
local: LocalSessionAccount;
|
|
7
|
+
remote: RemoteSessionAccount;
|
|
8
|
+
};
|
|
9
|
+
export declare function createUserSession(localAccount: LocalSessionAccount, remoteAccount: RemoteSessionAccount): UserSession;
|
|
10
|
+
type Params = {
|
|
11
|
+
storage: StorageAdapter;
|
|
12
|
+
};
|
|
13
|
+
export declare const createSsoSessionRepository: ({ storage }: Params) => {
|
|
14
|
+
add(value: UserSession): import("neverthrow").ResultAsync<UserSession, Error>;
|
|
15
|
+
filter(fn: (value: UserSession) => boolean): import("neverthrow").ResultAsync<UserSession[], Error>;
|
|
16
|
+
mutate(fn: (value: UserSession[]) => UserSession[]): import("neverthrow").ResultAsync<UserSession[], Error>;
|
|
17
|
+
read(): import("neverthrow").ResultAsync<UserSession[], Error>;
|
|
18
|
+
write(value: UserSession[]): import("neverthrow").ResultAsync<UserSession[], Error> | import("neverthrow").ResultAsync<null, Error>;
|
|
19
|
+
clear(): import("neverthrow").ResultAsync<void, Error>;
|
|
20
|
+
subscribe(fn: (value: UserSession[]) => void): VoidFunction;
|
|
21
|
+
};
|
|
22
|
+
export {};
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { LocalSessionAccountCodec, RemoteSessionAccountCodec } from '@novasamatech/statement-store';
|
|
2
|
+
import { fieldListView } from '@novasamatech/storage-adapter';
|
|
3
|
+
import { fromHex, toHex } from '@polkadot-api/utils';
|
|
4
|
+
import { nanoid } from 'nanoid';
|
|
5
|
+
import { Struct, Vector, str } from 'scale-ts';
|
|
6
|
+
const userSessionCodec = Struct({
|
|
7
|
+
id: str,
|
|
8
|
+
local: LocalSessionAccountCodec,
|
|
9
|
+
remote: RemoteSessionAccountCodec,
|
|
10
|
+
});
|
|
11
|
+
export function createUserSession(localAccount, remoteAccount) {
|
|
12
|
+
return {
|
|
13
|
+
id: nanoid(12),
|
|
14
|
+
local: localAccount,
|
|
15
|
+
remote: remoteAccount,
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
const userSessionsCodec = Vector(userSessionCodec);
|
|
19
|
+
export const createSsoSessionRepository = ({ storage }) => {
|
|
20
|
+
return fieldListView({
|
|
21
|
+
storage,
|
|
22
|
+
key: 'SsoSessions',
|
|
23
|
+
initial: [],
|
|
24
|
+
from: x => userSessionsCodec.dec(fromHex(x)),
|
|
25
|
+
to: x => toHex(userSessionsCodec.enc(x)),
|
|
26
|
+
});
|
|
27
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const hexCodec: import("scale-ts").Codec<`0x${string}`>;
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
export declare const RemoteMessageCodec: import("scale-ts").Codec<{
|
|
2
|
+
messageId: string;
|
|
3
|
+
data: {
|
|
4
|
+
tag: "v1";
|
|
5
|
+
value: {
|
|
6
|
+
tag: "Disconnected";
|
|
7
|
+
value: undefined;
|
|
8
|
+
} | {
|
|
9
|
+
tag: "SignRequest";
|
|
10
|
+
value: {
|
|
11
|
+
address: string;
|
|
12
|
+
blockHash: `0x${string}`;
|
|
13
|
+
blockNumber: `0x${string}`;
|
|
14
|
+
era: `0x${string}`;
|
|
15
|
+
genesisHash: `0x${string}`;
|
|
16
|
+
method: string;
|
|
17
|
+
nonce: `0x${string}`;
|
|
18
|
+
specVersion: `0x${string}`;
|
|
19
|
+
tip: `0x${string}`;
|
|
20
|
+
transactionVersion: `0x${string}`;
|
|
21
|
+
signedExtensions: string[];
|
|
22
|
+
version: number;
|
|
23
|
+
assetId: `0x${string}` | undefined;
|
|
24
|
+
mode: number | undefined;
|
|
25
|
+
withSignedTransaction: boolean | undefined;
|
|
26
|
+
};
|
|
27
|
+
} | {
|
|
28
|
+
tag: "SignResponse";
|
|
29
|
+
value: {
|
|
30
|
+
respondingTo: string;
|
|
31
|
+
payload: {
|
|
32
|
+
tag: "signature";
|
|
33
|
+
value: Uint8Array<ArrayBufferLike>;
|
|
34
|
+
} | {
|
|
35
|
+
tag: "signedTransaction";
|
|
36
|
+
value: Uint8Array<ArrayBufferLike>;
|
|
37
|
+
};
|
|
38
|
+
};
|
|
39
|
+
};
|
|
40
|
+
};
|
|
41
|
+
}>;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { Enum, Struct, _void, str } from 'scale-ts';
|
|
2
|
+
import { SignPayloadRequestCodec } from './signPayloadRequest.js';
|
|
3
|
+
import { SignPayloadResponseCodec } from './signPayloadResponse.js';
|
|
4
|
+
export const RemoteMessageCodec = Struct({
|
|
5
|
+
messageId: str,
|
|
6
|
+
data: Enum({
|
|
7
|
+
v1: Enum({
|
|
8
|
+
Disconnected: _void,
|
|
9
|
+
SignRequest: SignPayloadRequestCodec,
|
|
10
|
+
SignResponse: SignPayloadResponseCodec,
|
|
11
|
+
}),
|
|
12
|
+
}),
|
|
13
|
+
});
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { CodecType } from 'scale-ts';
|
|
2
|
+
export type SignPayloadRequest = CodecType<typeof SignPayloadRequestCodec>;
|
|
3
|
+
export declare const SignPayloadRequestCodec: import("scale-ts").Codec<{
|
|
4
|
+
address: string;
|
|
5
|
+
blockHash: `0x${string}`;
|
|
6
|
+
blockNumber: `0x${string}`;
|
|
7
|
+
era: `0x${string}`;
|
|
8
|
+
genesisHash: `0x${string}`;
|
|
9
|
+
method: string;
|
|
10
|
+
nonce: `0x${string}`;
|
|
11
|
+
specVersion: `0x${string}`;
|
|
12
|
+
tip: `0x${string}`;
|
|
13
|
+
transactionVersion: `0x${string}`;
|
|
14
|
+
signedExtensions: string[];
|
|
15
|
+
version: number;
|
|
16
|
+
assetId: `0x${string}` | undefined;
|
|
17
|
+
mode: number | undefined;
|
|
18
|
+
withSignedTransaction: boolean | undefined;
|
|
19
|
+
}>;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { Option, Struct, Vector, bool, str, u32 } from 'scale-ts';
|
|
2
|
+
import { hexCodec } from './hex.js';
|
|
3
|
+
export const SignPayloadRequestCodec = Struct({
|
|
4
|
+
address: str,
|
|
5
|
+
blockHash: hexCodec,
|
|
6
|
+
blockNumber: hexCodec,
|
|
7
|
+
era: hexCodec,
|
|
8
|
+
genesisHash: hexCodec,
|
|
9
|
+
method: str,
|
|
10
|
+
nonce: hexCodec,
|
|
11
|
+
specVersion: hexCodec,
|
|
12
|
+
tip: hexCodec,
|
|
13
|
+
transactionVersion: hexCodec,
|
|
14
|
+
signedExtensions: Vector(str),
|
|
15
|
+
version: u32,
|
|
16
|
+
assetId: Option(hexCodec),
|
|
17
|
+
mode: Option(u32),
|
|
18
|
+
withSignedTransaction: Option(bool),
|
|
19
|
+
});
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { CodecType } from 'scale-ts';
|
|
2
|
+
export type SignPayloadResponse = CodecType<typeof SignPayloadResponseCodec>;
|
|
3
|
+
export declare const SignPayloadResponseCodec: import("scale-ts").Codec<{
|
|
4
|
+
respondingTo: string;
|
|
5
|
+
payload: {
|
|
6
|
+
tag: "signature";
|
|
7
|
+
value: Uint8Array<ArrayBufferLike>;
|
|
8
|
+
} | {
|
|
9
|
+
tag: "signedTransaction";
|
|
10
|
+
value: Uint8Array<ArrayBufferLike>;
|
|
11
|
+
};
|
|
12
|
+
}>;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { CodecType } from 'scale-ts';
|
|
2
|
+
export type SignRequest = CodecType<typeof SignRequestCodec>;
|
|
3
|
+
export declare const SignRequestCodec: import("scale-ts").Codec<{
|
|
4
|
+
address: string;
|
|
5
|
+
blockHash: `0x${string}`;
|
|
6
|
+
blockNumber: `0x${string}`;
|
|
7
|
+
era: `0x${string}`;
|
|
8
|
+
genesisHash: `0x${string}`;
|
|
9
|
+
method: string;
|
|
10
|
+
nonce: `0x${string}`;
|
|
11
|
+
specVersion: `0x${string}`;
|
|
12
|
+
tip: `0x${string}`;
|
|
13
|
+
transactionVersion: `0x${string}`;
|
|
14
|
+
signedExtensions: string[];
|
|
15
|
+
version: number;
|
|
16
|
+
assetId: `0x${string}` | undefined;
|
|
17
|
+
mode: number | undefined;
|
|
18
|
+
withSignedTransaction: boolean | undefined;
|
|
19
|
+
}>;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { Option, Struct, Vector, bool, str, u32 } from 'scale-ts';
|
|
2
|
+
import { hexCodec } from './hex.js';
|
|
3
|
+
export const SignRequestCodec = Struct({
|
|
4
|
+
address: str,
|
|
5
|
+
blockHash: hexCodec,
|
|
6
|
+
blockNumber: hexCodec,
|
|
7
|
+
era: hexCodec,
|
|
8
|
+
genesisHash: hexCodec,
|
|
9
|
+
method: str,
|
|
10
|
+
nonce: hexCodec,
|
|
11
|
+
specVersion: hexCodec,
|
|
12
|
+
tip: hexCodec,
|
|
13
|
+
transactionVersion: hexCodec,
|
|
14
|
+
signedExtensions: Vector(str),
|
|
15
|
+
version: u32,
|
|
16
|
+
assetId: Option(hexCodec),
|
|
17
|
+
mode: Option(u32),
|
|
18
|
+
withSignedTransaction: Option(bool),
|
|
19
|
+
});
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { CodecType } from 'scale-ts';
|
|
2
|
+
export type SignResponse = CodecType<typeof SignResponseCodec>;
|
|
3
|
+
export declare const SignResponseCodec: import("scale-ts").Codec<{
|
|
4
|
+
signature: Uint8Array<ArrayBufferLike>;
|
|
5
|
+
SignedTransaction: Uint8Array<ArrayBufferLike>;
|
|
6
|
+
}>;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { Encryption, StatementProver, StatementStoreAdapter } from '@novasamatech/statement-store';
|
|
2
|
+
import type { StorageAdapter } from '@novasamatech/storage-adapter';
|
|
3
|
+
import { ResultAsync } from 'neverthrow';
|
|
4
|
+
import type { CodecType } from 'scale-ts';
|
|
5
|
+
import type { Callback } from '../../types.js';
|
|
6
|
+
import type { UserSession } from '../ssoSessionRepository.js';
|
|
7
|
+
import { RemoteMessageCodec, RemoteMessageDataCodec } from './scale/remoteMessage.js';
|
|
8
|
+
export type SsoSession = ReturnType<typeof createSsoSession>;
|
|
9
|
+
export declare function createSsoSession({ userSession, statementStore, encryption, storage, prover, }: {
|
|
10
|
+
userSession: UserSession;
|
|
11
|
+
statementStore: StatementStoreAdapter;
|
|
12
|
+
encryption: Encryption;
|
|
13
|
+
storage: StorageAdapter;
|
|
14
|
+
prover: StatementProver;
|
|
15
|
+
}): {
|
|
16
|
+
request(message: CodecType<typeof RemoteMessageDataCodec>): ResultAsync<{
|
|
17
|
+
requestId: string;
|
|
18
|
+
}, Error>;
|
|
19
|
+
sendDisconnectMessage(): ResultAsync<{
|
|
20
|
+
requestId: string;
|
|
21
|
+
}, Error>;
|
|
22
|
+
subscribe(callback: Callback<CodecType<typeof RemoteMessageCodec>, ResultAsync<boolean, Error>>): VoidFunction;
|
|
23
|
+
};
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { createSession } from '@novasamatech/statement-store';
|
|
2
|
+
import { fieldListView } from '@novasamatech/storage-adapter';
|
|
3
|
+
import { nanoid } from 'nanoid';
|
|
4
|
+
import { ResultAsync, okAsync } from 'neverthrow';
|
|
5
|
+
import { RemoteMessageCodec, RemoteMessageDataCodec } from './scale/remoteMessage.js';
|
|
6
|
+
export function createSsoSession({ userSession, statementStore, encryption, storage, prover, }) {
|
|
7
|
+
const session = createSession({
|
|
8
|
+
localAccount: userSession.local,
|
|
9
|
+
remoteAccount: userSession.remote,
|
|
10
|
+
statementStore,
|
|
11
|
+
encryption,
|
|
12
|
+
prover,
|
|
13
|
+
});
|
|
14
|
+
const processedMessages = fieldListView({
|
|
15
|
+
storage,
|
|
16
|
+
key: `sso_processed_${userSession.id}`,
|
|
17
|
+
from: JSON.parse,
|
|
18
|
+
to: JSON.stringify,
|
|
19
|
+
initial: [],
|
|
20
|
+
});
|
|
21
|
+
return {
|
|
22
|
+
request(message) {
|
|
23
|
+
return session.submitRequest(RemoteMessageCodec, {
|
|
24
|
+
messageId: nanoid(),
|
|
25
|
+
data: message,
|
|
26
|
+
});
|
|
27
|
+
},
|
|
28
|
+
sendDisconnectMessage() {
|
|
29
|
+
return session.submitRequest(RemoteMessageCodec, {
|
|
30
|
+
messageId: nanoid(),
|
|
31
|
+
data: {
|
|
32
|
+
tag: 'v1',
|
|
33
|
+
value: {
|
|
34
|
+
tag: 'Disconnected',
|
|
35
|
+
value: undefined,
|
|
36
|
+
},
|
|
37
|
+
},
|
|
38
|
+
});
|
|
39
|
+
},
|
|
40
|
+
subscribe(callback) {
|
|
41
|
+
return session.subscribe(RemoteMessageCodec, messages => {
|
|
42
|
+
processedMessages.read().andThen(processed => {
|
|
43
|
+
const results = messages.map(message => {
|
|
44
|
+
if (message.type === 'request') {
|
|
45
|
+
const isMessageProcessed = processed.includes(message.data.messageId);
|
|
46
|
+
if (isMessageProcessed) {
|
|
47
|
+
return okAsync({ processed: false });
|
|
48
|
+
}
|
|
49
|
+
return callback(message.data)
|
|
50
|
+
.orTee(error => {
|
|
51
|
+
console.error('Error while processing sso messsage:', error);
|
|
52
|
+
})
|
|
53
|
+
.orElse(() => okAsync(false))
|
|
54
|
+
.map(processed => (processed ? { processed, message: message.data } : { processed }));
|
|
55
|
+
}
|
|
56
|
+
return okAsync({ processed: false });
|
|
57
|
+
});
|
|
58
|
+
return ResultAsync.combine(results).andThen(results => {
|
|
59
|
+
const newMessages = results.filter(x => x.processed).map(x => x.message.messageId);
|
|
60
|
+
if (newMessages.length > 0) {
|
|
61
|
+
return processedMessages.mutate(x => x.concat(newMessages));
|
|
62
|
+
}
|
|
63
|
+
return okAsync();
|
|
64
|
+
});
|
|
65
|
+
});
|
|
66
|
+
});
|
|
67
|
+
},
|
|
68
|
+
};
|
|
69
|
+
}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { StatementProver } from '@novasamatech/statement-store';
|
|
2
|
+
import type { UserSession } from '../ssoSessionRepository.js';
|
|
3
|
+
import type { UserSecretRepository } from '../userSecretRepository.js';
|
|
4
|
+
export declare function createSsoStatementProver(userSession: UserSession, userSecretRepository: UserSecretRepository): StatementProver;
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { getStatementSigner, statementCodec } from '@polkadot-api/sdk-statement';
|
|
2
|
+
import { err, errAsync, fromThrowable, ok, okAsync } from 'neverthrow';
|
|
3
|
+
import { compact } from 'scale-ts';
|
|
4
|
+
import { toError } from '../../helpers/utils.js';
|
|
5
|
+
import { getSsPub, signWithSsSecret, verifyWithSsSecret } from '../../modules/crypto.js';
|
|
6
|
+
const verify = fromThrowable(verifyWithSsSecret, toError);
|
|
7
|
+
export function createSsoStatementProver(userSession, userSecretRepository) {
|
|
8
|
+
const secret = userSecretRepository
|
|
9
|
+
.read(userSession.id)
|
|
10
|
+
.andThen(secrets => (secrets ? ok(secrets) : err(new Error(`Secrets for session ${userSession.id} not found.`))))
|
|
11
|
+
.map(x => x.ssSecret);
|
|
12
|
+
return {
|
|
13
|
+
generateMessageProof(statement) {
|
|
14
|
+
return secret.map(secret => {
|
|
15
|
+
const signer = getStatementSigner(getSsPub(secret), 'sr25519', data => signWithSsSecret(secret, data));
|
|
16
|
+
return signer.sign(statement);
|
|
17
|
+
});
|
|
18
|
+
},
|
|
19
|
+
verifyMessageProof(statement) {
|
|
20
|
+
const { proof, ...unsigned } = statement;
|
|
21
|
+
if (!proof) {
|
|
22
|
+
// TODO should we pass check when proof is not presented?
|
|
23
|
+
return okAsync(true);
|
|
24
|
+
}
|
|
25
|
+
const encoded = statementCodec.enc(unsigned);
|
|
26
|
+
const compactLen = compact.enc(compact.dec(encoded)).length;
|
|
27
|
+
switch (proof.type) {
|
|
28
|
+
case 'sr25519':
|
|
29
|
+
return verify(encoded.slice(compactLen), proof.value.signature.asBytes(), proof.value.signer.asBytes()).asyncAndThen(x => okAsync(x));
|
|
30
|
+
default:
|
|
31
|
+
return errAsync(new Error(`Proof type ${proof.type} is not supported.`));
|
|
32
|
+
}
|
|
33
|
+
},
|
|
34
|
+
};
|
|
35
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { Encryption, StatementProver, StatementStoreAdapter } from '@novasamatech/statement-store';
|
|
2
|
+
import type { StorageAdapter } from '@novasamatech/storage-adapter';
|
|
3
|
+
import { ResultAsync } from 'neverthrow';
|
|
4
|
+
import type { CodecType } from 'scale-ts';
|
|
5
|
+
import type { Callback } from '../../types.js';
|
|
6
|
+
import type { StoredUserSession } from '../userSessionRepository.js';
|
|
7
|
+
import { RemoteMessageCodec } from './scale/remoteMessage.js';
|
|
8
|
+
import type { SignPayloadRequest } from './scale/signPayloadRequest.js';
|
|
9
|
+
import type { SignPayloadResponse } from './scale/signPayloadResponse.js';
|
|
10
|
+
export type UserSession = StoredUserSession & {
|
|
11
|
+
sendDisconnectMessage(): ResultAsync<void, Error>;
|
|
12
|
+
signPayload(payload: SignPayloadRequest): ResultAsync<SignPayloadResponse, Error>;
|
|
13
|
+
subscribe(callback: Callback<CodecType<typeof RemoteMessageCodec>, ResultAsync<boolean, Error>>): VoidFunction;
|
|
14
|
+
dispose(): void;
|
|
15
|
+
};
|
|
16
|
+
export declare function createUserSession({ userSession, statementStore, encryption, storage, prover, }: {
|
|
17
|
+
userSession: StoredUserSession;
|
|
18
|
+
statementStore: StatementStoreAdapter;
|
|
19
|
+
encryption: Encryption;
|
|
20
|
+
storage: StorageAdapter;
|
|
21
|
+
prover: StatementProver;
|
|
22
|
+
}): UserSession;
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import { createSession } from '@novasamatech/statement-store';
|
|
2
|
+
import { fieldListView } from '@novasamatech/storage-adapter';
|
|
3
|
+
import { AccountId } from '@polkadot-api/substrate-bindings';
|
|
4
|
+
import { toHex } from '@polkadot-api/utils';
|
|
5
|
+
import { nanoid } from 'nanoid';
|
|
6
|
+
import { ResultAsync, err, errAsync, ok, okAsync } from 'neverthrow';
|
|
7
|
+
import { RemoteMessageCodec } from './scale/remoteMessage.js';
|
|
8
|
+
export function createUserSession({ userSession, statementStore, encryption, storage, prover, }) {
|
|
9
|
+
const session = createSession({
|
|
10
|
+
localAccount: userSession.localAccount,
|
|
11
|
+
remoteAccount: userSession.remoteAccount,
|
|
12
|
+
statementStore,
|
|
13
|
+
encryption,
|
|
14
|
+
prover,
|
|
15
|
+
});
|
|
16
|
+
const processedMessages = fieldListView({
|
|
17
|
+
storage,
|
|
18
|
+
key: `sso_processed_${userSession.id}`,
|
|
19
|
+
from: JSON.parse,
|
|
20
|
+
to: JSON.stringify,
|
|
21
|
+
});
|
|
22
|
+
return {
|
|
23
|
+
id: userSession.id,
|
|
24
|
+
localAccount: userSession.localAccount,
|
|
25
|
+
remoteAccount: userSession.remoteAccount,
|
|
26
|
+
signPayload(payload) {
|
|
27
|
+
const accountId = AccountId();
|
|
28
|
+
if (toHex(accountId.enc(payload.address)) !== toHex(userSession.remoteAccount.accountId)) {
|
|
29
|
+
return errAsync(new Error(`Invalid address, got ${payload.address}`));
|
|
30
|
+
}
|
|
31
|
+
const messageId = nanoid();
|
|
32
|
+
const request = session.request(RemoteMessageCodec, {
|
|
33
|
+
messageId,
|
|
34
|
+
data: {
|
|
35
|
+
tag: 'v1',
|
|
36
|
+
value: {
|
|
37
|
+
tag: 'SignRequest',
|
|
38
|
+
value: payload,
|
|
39
|
+
},
|
|
40
|
+
},
|
|
41
|
+
});
|
|
42
|
+
return request
|
|
43
|
+
.andThen(() => session.waitForRequestMessage(RemoteMessageCodec, message => message.messageId === messageId))
|
|
44
|
+
.andThen(message => {
|
|
45
|
+
const { data } = message.payload;
|
|
46
|
+
switch (data.tag) {
|
|
47
|
+
case 'v1': {
|
|
48
|
+
switch (data.value.tag) {
|
|
49
|
+
case 'SignResponse':
|
|
50
|
+
return ok(data.value.value);
|
|
51
|
+
default:
|
|
52
|
+
return err(new Error(`Incorrect sign response: ${data.value.tag}`));
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
default:
|
|
56
|
+
return err(new Error(`Unsupported message version ${data.tag}`));
|
|
57
|
+
}
|
|
58
|
+
});
|
|
59
|
+
},
|
|
60
|
+
sendDisconnectMessage() {
|
|
61
|
+
return session
|
|
62
|
+
.submitRequestMessage(RemoteMessageCodec, {
|
|
63
|
+
messageId: nanoid(),
|
|
64
|
+
data: {
|
|
65
|
+
tag: 'v1',
|
|
66
|
+
value: {
|
|
67
|
+
tag: 'Disconnected',
|
|
68
|
+
value: undefined,
|
|
69
|
+
},
|
|
70
|
+
},
|
|
71
|
+
})
|
|
72
|
+
.map(() => undefined);
|
|
73
|
+
},
|
|
74
|
+
subscribe(callback) {
|
|
75
|
+
return session.subscribe(RemoteMessageCodec, messages => {
|
|
76
|
+
processedMessages.read().andThen(processed => {
|
|
77
|
+
const results = messages.map(message => {
|
|
78
|
+
if (message.type === 'request') {
|
|
79
|
+
const isMessageProcessed = processed.includes(message.payload.messageId);
|
|
80
|
+
if (isMessageProcessed) {
|
|
81
|
+
return okAsync({ processed: false });
|
|
82
|
+
}
|
|
83
|
+
return callback(message.payload)
|
|
84
|
+
.orTee(error => {
|
|
85
|
+
console.error('Error while processing sso messsage:', error);
|
|
86
|
+
})
|
|
87
|
+
.orElse(() => okAsync(false))
|
|
88
|
+
.map(processed => (processed ? { processed, message: message.payload } : { processed }));
|
|
89
|
+
}
|
|
90
|
+
return okAsync({ processed: false });
|
|
91
|
+
});
|
|
92
|
+
return ResultAsync.combine(results).andThen(results => {
|
|
93
|
+
const newMessages = results.filter(x => x.processed).map(x => x.message.messageId);
|
|
94
|
+
if (newMessages.length > 0) {
|
|
95
|
+
return processedMessages.mutate(x => x.concat(newMessages));
|
|
96
|
+
}
|
|
97
|
+
return okAsync();
|
|
98
|
+
});
|
|
99
|
+
});
|
|
100
|
+
});
|
|
101
|
+
},
|
|
102
|
+
dispose() {
|
|
103
|
+
return session.dispose();
|
|
104
|
+
},
|
|
105
|
+
};
|
|
106
|
+
}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { StatementProver } from '@novasamatech/statement-store';
|
|
2
|
+
import type { UserSecretRepository } from './userSecretRepository.js';
|
|
3
|
+
import type { StoredUserSession } from './userSessionRepository.js';
|
|
4
|
+
export declare function createSsoStatementProver(userSession: StoredUserSession, userSecretRepository: UserSecretRepository): StatementProver;
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { getStatementSigner, statementCodec } from '@polkadot-api/sdk-statement';
|
|
2
|
+
import { err, errAsync, fromThrowable, ok, okAsync } from 'neverthrow';
|
|
3
|
+
import { compact } from 'scale-ts';
|
|
4
|
+
import { getSsPub, signWithSsSecret, verifyWithSsSecret } from '../crypto.js';
|
|
5
|
+
import { toError } from '../helpers/utils.js';
|
|
6
|
+
const verify = fromThrowable(verifyWithSsSecret, toError);
|
|
7
|
+
export function createSsoStatementProver(userSession, userSecretRepository) {
|
|
8
|
+
const secret = userSecretRepository
|
|
9
|
+
.read(userSession.id)
|
|
10
|
+
.andThen(secrets => (secrets ? ok(secrets) : err(new Error(`Secrets for session ${userSession.id} not found.`))))
|
|
11
|
+
.map(x => x.ssSecret);
|
|
12
|
+
return {
|
|
13
|
+
generateMessageProof(statement) {
|
|
14
|
+
return secret.map(secret => {
|
|
15
|
+
const signer = getStatementSigner(getSsPub(secret), 'sr25519', data => signWithSsSecret(secret, data));
|
|
16
|
+
return signer.sign(statement);
|
|
17
|
+
});
|
|
18
|
+
},
|
|
19
|
+
verifyMessageProof(statement) {
|
|
20
|
+
const { proof, ...unsigned } = statement;
|
|
21
|
+
if (!proof) {
|
|
22
|
+
// TODO should we pass check when proof is not presented?
|
|
23
|
+
return okAsync(true);
|
|
24
|
+
}
|
|
25
|
+
const encoded = statementCodec.enc(unsigned);
|
|
26
|
+
const compactLen = compact.enc(compact.dec(encoded)).length;
|
|
27
|
+
switch (proof.type) {
|
|
28
|
+
case 'sr25519':
|
|
29
|
+
return verify(encoded.slice(compactLen), proof.value.signature.asBytes(), proof.value.signer.asBytes()).asyncAndThen(x => okAsync(x));
|
|
30
|
+
default:
|
|
31
|
+
return errAsync(new Error(`Proof type ${proof.type} is not supported.`));
|
|
32
|
+
}
|
|
33
|
+
},
|
|
34
|
+
};
|
|
35
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { LocalSessionAccount, RemoteSessionAccount } from '@novasamatech/statement-store';
|
|
2
|
+
import type { StorageAdapter } from '@novasamatech/storage-adapter';
|
|
3
|
+
export type SsoSessionRepository = ReturnType<typeof createSsoSessionRepository>;
|
|
4
|
+
export type UserSession = {
|
|
5
|
+
id: string;
|
|
6
|
+
local: LocalSessionAccount;
|
|
7
|
+
remote: RemoteSessionAccount;
|
|
8
|
+
};
|
|
9
|
+
export declare function createUserSession(localAccount: LocalSessionAccount, remoteAccount: RemoteSessionAccount): UserSession;
|
|
10
|
+
export declare const createSsoSessionRepository: (storage: StorageAdapter) => {
|
|
11
|
+
add(value: UserSession): import("neverthrow").ResultAsync<UserSession, Error>;
|
|
12
|
+
filter(fn: (value: UserSession) => boolean): import("neverthrow").ResultAsync<UserSession[], Error>;
|
|
13
|
+
mutate(fn: (value: UserSession[]) => UserSession[]): import("neverthrow").ResultAsync<UserSession[], Error>;
|
|
14
|
+
read(): import("neverthrow").ResultAsync<UserSession[], Error>;
|
|
15
|
+
write(value: UserSession[]): import("neverthrow").ResultAsync<UserSession[], Error> | import("neverthrow").ResultAsync<null, Error>;
|
|
16
|
+
clear(): import("neverthrow").ResultAsync<void, Error>;
|
|
17
|
+
subscribe(fn: (value: UserSession[]) => void): VoidFunction;
|
|
18
|
+
};
|