@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.
Files changed (184) hide show
  1. package/.papi/descriptors/dist/common-types.d.ts +8667 -0
  2. package/.papi/descriptors/dist/common.d.ts +1 -0
  3. package/.papi/descriptors/dist/descriptors-UUEW32EL.mjs +27 -0
  4. package/.papi/descriptors/dist/descriptors.d.ts +1 -0
  5. package/.papi/descriptors/dist/index.d.ts +10 -0
  6. package/.papi/descriptors/dist/index.js +237 -0
  7. package/.papi/descriptors/dist/index.mjs +148 -0
  8. package/.papi/descriptors/dist/metadataTypes-E4AQJDJR.mjs +6 -0
  9. package/.papi/descriptors/dist/metadataTypes.d.ts +2 -0
  10. package/.papi/descriptors/dist/people_lite.d.ts +7757 -0
  11. package/.papi/descriptors/dist/people_lite_metadata-EIVHV27X.mjs +6 -0
  12. package/.papi/descriptors/dist/people_lite_metadata.d.ts +2 -0
  13. package/.papi/descriptors/package.json +24 -0
  14. package/.papi/metadata/people_lite.scale +0 -0
  15. package/.papi/polkadot-api.json +15 -0
  16. package/dist/adapters/identity/rpc.d.ts +6 -4
  17. package/dist/adapters/identity/rpc.js +96 -26
  18. package/dist/adapters/identity/types.d.ts +3 -1
  19. package/dist/adapters/lazyClient/papi.js +5 -0
  20. package/dist/adapters/lazyClient/types.d.ts +1 -0
  21. package/dist/adapters/statement/rpc.js +58 -10
  22. package/dist/adapters/statement/types.d.ts +6 -3
  23. package/dist/adapters/storage/localStorage.js +26 -4
  24. package/dist/adapters/storage/memory.js +14 -4
  25. package/dist/adapters/storage/types.d.ts +5 -2
  26. package/dist/adapters/storage/types.js +1 -1
  27. package/dist/components/auth/codec.d.ts +9 -0
  28. package/dist/components/auth/codec.js +10 -0
  29. package/dist/components/auth/codecs.d.ts +9 -0
  30. package/dist/components/auth/codecs.js +10 -0
  31. package/dist/components/auth/index.d.ts +36 -0
  32. package/dist/components/auth/index.js +150 -0
  33. package/dist/components/auth/types.d.ts +15 -0
  34. package/dist/components/auth/types.js +1 -0
  35. package/dist/components/session.d.ts +34 -0
  36. package/dist/components/session.js +54 -0
  37. package/dist/components/sso/index.d.ts +36 -0
  38. package/dist/components/sso/index.js +150 -0
  39. package/dist/components/sso/scale/handshake.d.ts +9 -0
  40. package/dist/components/sso/scale/handshake.js +10 -0
  41. package/dist/components/sso/types.d.ts +15 -0
  42. package/dist/components/sso/types.js +1 -0
  43. package/dist/components/transport.d.ts +27 -0
  44. package/dist/components/transport.js +57 -0
  45. package/dist/components/user/codec.d.ts +16 -0
  46. package/dist/components/user/codec.js +13 -0
  47. package/dist/components/user/index.d.ts +22 -0
  48. package/dist/components/user/index.js +58 -0
  49. package/dist/components/user/ssoMessageStream.d.ts +10 -0
  50. package/dist/components/user/ssoMessageStream.js +8 -0
  51. package/dist/components/user/ssoSession.d.ts +5 -0
  52. package/dist/components/user/ssoSession.js +5 -0
  53. package/dist/components/user/storage.d.ts +27 -0
  54. package/dist/components/user/storage.js +143 -0
  55. package/dist/components/user/types.d.ts +6 -0
  56. package/dist/components/user/types.js +1 -0
  57. package/dist/components/user/userSessionStorage.d.ts +20 -0
  58. package/dist/components/user/userSessionStorage.js +24 -0
  59. package/dist/components/user.d.ts +74 -0
  60. package/dist/components/user.js +188 -0
  61. package/dist/constants.d.ts +2 -1
  62. package/dist/constants.js +5 -1
  63. package/dist/crypto.d.ts +29 -0
  64. package/dist/crypto.js +86 -0
  65. package/dist/helpers/abortError.d.ts +4 -0
  66. package/dist/helpers/abortError.js +8 -0
  67. package/dist/helpers/callbackRaceResolver.d.ts +1 -0
  68. package/dist/helpers/callbackRaceResolver.js +17 -0
  69. package/dist/helpers/result.d.ts +12 -0
  70. package/dist/helpers/result.js +15 -0
  71. package/dist/helpers/result.spec.d.ts +1 -0
  72. package/dist/helpers/result.spec.js +23 -0
  73. package/dist/helpers/state.d.ts +16 -0
  74. package/dist/helpers/state.js +51 -0
  75. package/dist/helpers/utils.d.ts +2 -1
  76. package/dist/helpers/utils.js +11 -2
  77. package/dist/helpers/zipWith.d.ts +4 -0
  78. package/dist/helpers/zipWith.js +11 -0
  79. package/dist/identity/impl.d.ts +6 -0
  80. package/dist/identity/impl.js +68 -0
  81. package/dist/identity/rpcAdapter.d.ts +3 -0
  82. package/dist/identity/rpcAdapter.js +46 -0
  83. package/dist/identity/types.d.ts +21 -0
  84. package/dist/identity/types.js +1 -0
  85. package/dist/index.d.ts +7 -3
  86. package/dist/index.js +2 -7
  87. package/dist/modules/crypto.d.ts +8 -9
  88. package/dist/modules/crypto.js +20 -42
  89. package/dist/modules/secretStorage.d.ts +13 -12
  90. package/dist/modules/secretStorage.js +34 -43
  91. package/dist/modules/session/helpers.d.ts +5 -0
  92. package/dist/modules/session/helpers.js +29 -0
  93. package/dist/modules/session/session.d.ts +12 -0
  94. package/dist/modules/session/session.js +50 -0
  95. package/dist/modules/session/types.d.ts +12 -0
  96. package/dist/modules/session/types.js +1 -0
  97. package/dist/modules/signIn.d.ts +32 -11
  98. package/dist/modules/signIn.js +98 -101
  99. package/dist/modules/state.d.ts +16 -0
  100. package/dist/modules/state.js +50 -0
  101. package/dist/modules/statementStore.d.ts +10 -11
  102. package/dist/modules/statementStore.js +16 -14
  103. package/dist/modules/statementTopic.d.ts +34 -0
  104. package/dist/modules/statementTopic.js +46 -0
  105. package/dist/modules/storageView.d.ts +25 -0
  106. package/dist/modules/storageView.js +51 -0
  107. package/dist/modules/syncStorage.d.ts +25 -0
  108. package/dist/modules/syncStorage.js +76 -0
  109. package/dist/modules/transport/codec.d.ts +24 -0
  110. package/dist/modules/transport/codec.js +36 -0
  111. package/dist/modules/transport/crypto.d.ts +2 -0
  112. package/dist/modules/transport/crypto.js +20 -0
  113. package/dist/modules/transport/transport.d.ts +42 -0
  114. package/dist/modules/transport/transport.js +66 -0
  115. package/dist/modules/user.d.ts +67 -0
  116. package/dist/modules/user.js +188 -0
  117. package/dist/modules/userManager.d.ts +15 -0
  118. package/dist/modules/userManager.js +105 -0
  119. package/dist/modules/userStorage.d.ts +19 -0
  120. package/dist/modules/userStorage.js +108 -0
  121. package/dist/modules/userStore.d.ts +15 -0
  122. package/dist/modules/userStore.js +105 -0
  123. package/dist/papp.d.ts +25 -13
  124. package/dist/papp.js +19 -50
  125. package/dist/sso/auth/attestationService.d.ts +18 -0
  126. package/dist/sso/auth/attestationService.js +171 -0
  127. package/dist/sso/auth/impl.d.ts +53 -0
  128. package/dist/sso/auth/impl.js +161 -0
  129. package/dist/sso/auth/scale/handshake.d.ts +9 -0
  130. package/dist/sso/auth/scale/handshake.js +10 -0
  131. package/dist/sso/auth/types.d.ts +17 -0
  132. package/dist/sso/auth/types.js +1 -0
  133. package/dist/sso/session/impl.d.ts +23 -0
  134. package/dist/sso/session/impl.js +57 -0
  135. package/dist/sso/session/scale/remoteMessage.d.ts +10 -0
  136. package/dist/sso/session/scale/remoteMessage.js +13 -0
  137. package/dist/sso/session/sessionManager.d.ts +23 -0
  138. package/dist/sso/session/sessionManager.js +58 -0
  139. package/dist/sso/session/ssoSession.d.ts +8 -0
  140. package/dist/sso/session/ssoSession.js +5 -0
  141. package/dist/sso/session/ssoSessionStorage.d.ts +21 -0
  142. package/dist/sso/session/ssoSessionStorage.js +20 -0
  143. package/dist/sso/session/types.d.ts +6 -0
  144. package/dist/sso/session/types.js +1 -0
  145. package/dist/sso/session/userSessionStorage.d.ts +21 -0
  146. package/dist/sso/session/userSessionStorage.js +20 -0
  147. package/dist/sso/sessionManager/attestationService.d.ts +5 -0
  148. package/dist/sso/sessionManager/attestationService.js +15 -0
  149. package/dist/sso/sessionManager/impl.d.ts +22 -0
  150. package/dist/sso/sessionManager/impl.js +71 -0
  151. package/dist/sso/sessionManager/repository/ssoSessionRepository.d.ts +22 -0
  152. package/dist/sso/sessionManager/repository/ssoSessionRepository.js +27 -0
  153. package/dist/sso/sessionManager/scale/hex.d.ts +1 -0
  154. package/dist/sso/sessionManager/scale/hex.js +3 -0
  155. package/dist/sso/sessionManager/scale/remoteMessage.d.ts +41 -0
  156. package/dist/sso/sessionManager/scale/remoteMessage.js +13 -0
  157. package/dist/sso/sessionManager/scale/signPayloadRequest.d.ts +19 -0
  158. package/dist/sso/sessionManager/scale/signPayloadRequest.js +19 -0
  159. package/dist/sso/sessionManager/scale/signPayloadResponse.d.ts +12 -0
  160. package/dist/sso/sessionManager/scale/signPayloadResponse.js +9 -0
  161. package/dist/sso/sessionManager/scale/signRequest.d.ts +19 -0
  162. package/dist/sso/sessionManager/scale/signRequest.js +19 -0
  163. package/dist/sso/sessionManager/scale/signResponse.d.ts +6 -0
  164. package/dist/sso/sessionManager/scale/signResponse.js +5 -0
  165. package/dist/sso/sessionManager/ssoSession.d.ts +23 -0
  166. package/dist/sso/sessionManager/ssoSession.js +69 -0
  167. package/dist/sso/sessionManager/ssoSessionProver.d.ts +4 -0
  168. package/dist/sso/sessionManager/ssoSessionProver.js +35 -0
  169. package/dist/sso/sessionManager/types.d.ts +6 -0
  170. package/dist/sso/sessionManager/types.js +1 -0
  171. package/dist/sso/sessionManager/userSession.d.ts +22 -0
  172. package/dist/sso/sessionManager/userSession.js +106 -0
  173. package/dist/sso/ssoSessionProver.d.ts +4 -0
  174. package/dist/sso/ssoSessionProver.js +35 -0
  175. package/dist/sso/ssoSessionRepository.d.ts +18 -0
  176. package/dist/sso/ssoSessionRepository.js +27 -0
  177. package/dist/sso/userSecretRepository.d.ts +17 -0
  178. package/dist/sso/userSecretRepository.js +45 -0
  179. package/dist/sso/userSessionRepository.d.ts +18 -0
  180. package/dist/sso/userSessionRepository.js +26 -0
  181. package/dist/structs.d.ts +10 -10
  182. package/dist/structs.js +17 -13
  183. package/dist/types.d.ts +1 -1
  184. package/package.json +14 -7
@@ -0,0 +1,50 @@
1
+ import { toHex } from '@polkadot-api/utils';
2
+ import { okAsync } from 'neverthrow';
3
+ import { storageListView } from '../storageView.js';
4
+ import { createSessionId } from './helpers.js';
5
+ export function createSession({ ownAccount, peerAccount, transport, storage, codec, }) {
6
+ // const ownSession = createSessionId(peerAccount.publicKey, ownAccount, peerAccount);
7
+ const peerSession = createSessionId(peerAccount.publicKey, peerAccount, ownAccount);
8
+ const processedStorage = storageListView({
9
+ key: `ProcessesMessages_${toHex(peerSession)}`,
10
+ storage,
11
+ initial: [],
12
+ from: JSON.parse,
13
+ to: JSON.stringify,
14
+ });
15
+ let subscriptions = [];
16
+ return {
17
+ subscribe(callback) {
18
+ const unsub = transport.subscribe({ ownAccount, peerAccount, codec }, async (messages) => {
19
+ processedStorage.read().map(processed => {
20
+ for (const message of messages) {
21
+ if (message.type === 'response')
22
+ continue;
23
+ if (processed.includes(message.requestId)) {
24
+ return okAsync();
25
+ }
26
+ callback(message.data).andThen(processed => {
27
+ if (processed) {
28
+ return processedStorage.mutate(p => p.concat(message.requestId));
29
+ }
30
+ else {
31
+ return okAsync();
32
+ }
33
+ });
34
+ }
35
+ });
36
+ });
37
+ subscriptions.push(unsub);
38
+ return () => {
39
+ unsub();
40
+ subscriptions = subscriptions.filter(x => x !== unsub);
41
+ };
42
+ },
43
+ dispose() {
44
+ for (const unsub of subscriptions) {
45
+ unsub();
46
+ }
47
+ subscriptions = [];
48
+ },
49
+ };
50
+ }
@@ -0,0 +1,12 @@
1
+ import type { ResultAsync } from 'neverthrow';
2
+ import type { Codec, CodecType } from 'scale-ts';
3
+ import type { Callback } from '../../types.js';
4
+ export type Session<T extends Codec<any>> = {
5
+ subscribe(callback: Callback<CodecType<T>, ResultAsync<boolean, Error>>): VoidFunction;
6
+ dispose(): void;
7
+ };
8
+ export type Account = {
9
+ accountId: Uint8Array;
10
+ publicKey: Uint8Array;
11
+ pin: string | undefined;
12
+ };
@@ -0,0 +1 @@
1
+ export {};
@@ -1,7 +1,8 @@
1
1
  import type { StatementAdapter } from '../adapters/statement/types.js';
2
2
  import type { StorageAdapter } from '../adapters/storage/types.js';
3
- import type { SessionTopic } from '../types.js';
3
+ import type { Result } from '../helpers/result.js';
4
4
  import type { EncrPublicKey, SsPublicKey } from './crypto.js';
5
+ import type { User } from './userManager.js';
5
6
  export declare const HandshakeData: import("scale-ts").Codec<{
6
7
  tag: "V1";
7
8
  value: [SsPublicKey, EncrPublicKey, string];
@@ -23,24 +24,44 @@ export type SignInStatus = {
23
24
  message: string;
24
25
  } | {
25
26
  step: 'finished';
26
- sessionTopic: SessionTopic;
27
- pappAccountId: string;
28
- };
29
- export type SignInResult = {
30
- sessionTopic: SessionTopic;
31
- pappAccountId: string;
27
+ user: User;
32
28
  };
33
29
  type Params = {
30
+ /**
31
+ * Host app Id.
32
+ * CAUTION! This value should be stable.
33
+ */
34
34
  appId: string;
35
+ /**
36
+ * URL for additional metadata that will be displayed during pairing process.
37
+ * Content of provided json shound be
38
+ * ```ts
39
+ * interface Metadata {
40
+ * name: string;
41
+ * icon: string; // url for icon. Icon should be a rasterized image with min size 256x256 px.
42
+ * }
43
+ * ```
44
+ */
35
45
  metadata: string;
36
46
  statements: StatementAdapter;
37
47
  storage: StorageAdapter;
38
48
  };
39
49
  export declare function createSignInFlow({ appId, metadata, statements, storage }: Params): {
40
- getSignedUser(): Promise<SignInResult | null>;
41
- signIn(): Promise<SignInResult | null>;
50
+ signInStatus: {
51
+ read(): SignInStatus;
52
+ write(value: SignInStatus): void;
53
+ reset(): void;
54
+ subscribe(fn: (value: SignInStatus) => void): import("nanoevents").Unsubscribe;
55
+ };
56
+ users: {
57
+ readSelectedUser(): Promise<Result<User | null>>;
58
+ readUser(accountId: string): Promise<Result<User | null>>;
59
+ createUser(user: User): Promise<Result<User>>;
60
+ removeUser(accountId: string): Promise<Result<void, Error>>;
61
+ readAccounts(): Promise<Result<string[], Error>>;
62
+ selectAccount(accountId: string): Promise<Result<void, Error>>;
63
+ };
64
+ signIn(): Promise<Result<User | null>>;
42
65
  abortSignIn(): void;
43
- getSignInStatus(): SignInStatus;
44
- onStatusChange(callback: (status: SignInStatus) => void): import("nanoevents").Unsubscribe;
45
66
  };
46
67
  export {};
@@ -1,10 +1,12 @@
1
1
  import { toHex } from '@polkadot-api/utils';
2
- import { createNanoEvents } from 'nanoevents';
3
2
  import { Bytes, Enum, Tuple, str } from 'scale-ts';
4
- import { isAbortError } from '../helpers/utils.js';
5
- import { ENCR_SECRET_SEED_SIZE, EncrPubKey, SS_SECRET_SEED_SIZE, SsPubKey, createEncrSecret, createSharedSecret, createSsSecret, createStableSeed, createSymmetricKey, decrypt, getEncrPub, getSsPub, khash, mergeBytes, stringToBytes, } from './crypto.js';
3
+ import { err, fromPromise, ok, seq } from '../helpers/result.js';
4
+ import { isAbortError, toError } from '../helpers/utils.js';
5
+ import { ENCR_SECRET_SEED_SIZE, EncrPubKey, SS_SECRET_SEED_SIZE, SsPubKey, createEncrSecret, createRandomSeed, createSharedSecret, createSsSecret, createSymmetricKey, decrypt, getEncrPub, getSsPub, khash, mergeBytes, stringToBytes, } from './crypto.js';
6
6
  import { createSecretStorage } from './secretStorage.js';
7
7
  import { createSession } from './statementStore.js';
8
+ import { createSyncStorage } from './syncStorage.js';
9
+ import { createUserManager } from './userManager.js';
8
10
  // codecs
9
11
  export const HandshakeData = Enum({
10
12
  V1: Tuple(SsPubKey, EncrPubKey, str),
@@ -15,101 +17,76 @@ export const HandshakeResponsePayload = Enum({
15
17
  });
16
18
  export const HandshakeResponseSensitiveData = Tuple(Bytes(65), Bytes(32));
17
19
  export function createSignInFlow({ appId, metadata, statements, storage }) {
20
+ const userManager = createUserManager(appId, storage);
18
21
  const secretStorage = createSecretStorage(appId, storage);
19
- const events = createNanoEvents();
20
- let signInStatus = { step: 'none' };
21
- events.on('status', status => {
22
- signInStatus = status;
23
- });
22
+ const signInStatus = createSyncStorage({ step: 'none' });
24
23
  let signInPromise = null;
25
24
  let abort = null;
26
- const signInFlow = {
27
- getSignedUser() {
28
- return Promise.all([secretStorage.readSessionTopic(), secretStorage.readPappAccountId()]).then(([existingSessionTopic, existingPappAccountId]) => {
29
- if (existingSessionTopic && existingPappAccountId) {
30
- events.emit('status', {
31
- step: 'finished',
32
- sessionTopic: existingSessionTopic,
33
- pappAccountId: existingPappAccountId,
25
+ async function handshake(signal) {
26
+ signInStatus.write({ step: 'initial' });
27
+ const secrets = await getSecretKeys(appId, secretStorage);
28
+ return secrets.andThenPromise(async ({ ssPublicKey, encrPublicKey, encrSecret }) => {
29
+ const handshakeTopic = createHandshakeTopic({ encrPublicKey, ssPublicKey });
30
+ const handshakePayload = createHandshakePayloadV1({ ssPublicKey, encrPublicKey, metadata });
31
+ signInStatus.write({ step: 'pairing', payload: createDeeplink(handshakePayload) });
32
+ const statementStoreResponse = fromPromise(waitForStatements(statements, handshakeTopic, signal, (statements, resolve) => {
33
+ for (const statement of [...statements].reverse()) {
34
+ if (!statement.data)
35
+ continue;
36
+ const { sessionTopic, accountId } = retrieveSessionTopic({
37
+ payload: statement.data.asBytes(),
38
+ encrSecret,
39
+ ssPublicKey,
34
40
  });
35
- return {
36
- sessionTopic: existingSessionTopic,
37
- pappAccountId: existingPappAccountId,
38
- };
41
+ resolve({ sessionTopic, accountId: toHex(accountId) });
42
+ break;
39
43
  }
40
- return null;
41
- });
42
- },
44
+ }), toError);
45
+ return statementStoreResponse
46
+ .then(x => x.andThenPromise(userManager.createUser))
47
+ .then(async (result) => result
48
+ .map(user => {
49
+ signInStatus.write({ step: 'finished', user });
50
+ return user;
51
+ })
52
+ .orElse(e => {
53
+ const error = toError(e);
54
+ if (isAbortError(error)) {
55
+ signInStatus.write({ step: 'none' });
56
+ return ok(null);
57
+ }
58
+ else {
59
+ signInStatus.write({ step: 'error', message: error.message });
60
+ return err(error);
61
+ }
62
+ }));
63
+ });
64
+ }
65
+ const signInFlow = {
66
+ signInStatus,
67
+ users: userManager,
43
68
  async signIn() {
44
69
  if (signInPromise) {
45
70
  return signInPromise;
46
71
  }
47
72
  abort = new AbortController();
48
- events.emit('status', { step: 'initial' });
49
- signInPromise = signInFlow
50
- .getSignedUser()
51
- .then(async (signedIn) => {
52
- if (signedIn) {
53
- events.emit('status', {
54
- step: 'finished',
55
- sessionTopic: signedIn.sessionTopic,
56
- pappAccountId: signedIn.pappAccountId,
57
- });
58
- return signedIn;
59
- }
60
- const { ssPublicKey, encrPublicKey, encrSecret } = await getSecretKeys(appId, secretStorage);
61
- const handshakeTopic = createHandshakeTopic({ encrPublicKey, ssPublicKey });
62
- const handshakePayload = createHandshakePayload({ ssPublicKey, encrPublicKey, metadata });
63
- events.emit('status', { step: 'pairing', payload: createDeeplink(handshakePayload) });
64
- return waitForStatements(statements, handshakeTopic, abort?.signal ?? null, (statements, resolve) => {
65
- for (const statement of [...statements].reverse()) {
66
- if (!statement.data)
67
- continue;
68
- const { sessionTopic, pappAccountId } = retrieveSessionTopic({
69
- payload: statement.data.asBytes(),
70
- encrSecret,
71
- ssPublicKey,
72
- });
73
- resolve({ sessionTopic, pappAccountId: toHex(pappAccountId) });
74
- break;
75
- }
76
- });
77
- })
78
- .then(async ({ sessionTopic, pappAccountId }) => {
79
- await secretStorage.writeSessionTopic(sessionTopic);
80
- await secretStorage.writePappAccountId(pappAccountId);
81
- events.emit('status', { step: 'finished', sessionTopic, pappAccountId });
82
- return { sessionTopic, pappAccountId };
83
- })
84
- .catch(e => {
85
- if (isAbortError(e)) {
86
- events.emit('status', { step: 'none' });
87
- return null;
88
- }
89
- events.emit('status', { step: 'error', message: e.message });
90
- throw e;
91
- });
73
+ signInPromise = handshake(abort.signal);
92
74
  return signInPromise;
93
75
  },
94
76
  abortSignIn() {
95
77
  if (abort) {
96
- events.emit('status', { step: 'none' });
78
+ signInPromise = null;
79
+ signInStatus.reset();
97
80
  abort.abort();
98
81
  }
99
82
  },
100
- getSignInStatus() {
101
- return signInStatus;
102
- },
103
- onStatusChange(callback) {
104
- return events.on('status', callback);
105
- },
106
83
  };
107
84
  return signInFlow;
108
85
  }
109
86
  function createHandshakeTopic({ encrPublicKey, ssPublicKey, }) {
110
87
  return khash(ssPublicKey, mergeBytes(encrPublicKey, stringToBytes('topic')));
111
88
  }
112
- function createHandshakePayload({ encrPublicKey, ssPublicKey, metadata, }) {
89
+ function createHandshakePayloadV1({ encrPublicKey, ssPublicKey, metadata, }) {
113
90
  return HandshakeData.enc({
114
91
  tag: 'V1',
115
92
  value: [ssPublicKey, encrPublicKey, metadata],
@@ -131,7 +108,6 @@ function retrieveSessionTopic({ payload, encrSecret, ssPublicKey, }) {
131
108
  const { encrypted, tmpKey } = parseHandshakePayload(payload);
132
109
  const symmetricKey = createSymmetricKey(createSharedSecret(encrSecret, tmpKey));
133
110
  const decrypted = decrypt(symmetricKey, encrypted);
134
- console.log('decrypted', decrypted.length, 65 + 32); // true
135
111
  const [pappEncrPublicKey, userPublicKey] = HandshakeResponseSensitiveData.dec(decrypted);
136
112
  const sharedSecret = createSharedSecret(encrSecret, pappEncrPublicKey);
137
113
  const session = createSession({
@@ -139,33 +115,48 @@ function retrieveSessionTopic({ payload, encrSecret, ssPublicKey, }) {
139
115
  accountA: ssPublicKey,
140
116
  accountB: pappEncrPublicKey,
141
117
  });
142
- console.log('userPublicKey', userPublicKey.length, toHex(userPublicKey));
143
- console.log('sessionTopic', session.a.length, toHex(session.a));
144
118
  return {
145
- pappAccountId: userPublicKey,
119
+ accountId: userPublicKey,
146
120
  sessionTopic: session.a,
147
121
  };
148
122
  }
123
+ async function getSsKeys(appId, secretStorage) {
124
+ return (await secretStorage.readSsSecret())
125
+ .andThenPromise(async (ssSecret) => {
126
+ if (ssSecret) {
127
+ return ok(ssSecret);
128
+ }
129
+ const seed = createRandomSeed(appId, SS_SECRET_SEED_SIZE);
130
+ const newSsSecret = createSsSecret(seed);
131
+ const write = await secretStorage.writeSsSecret(newSsSecret);
132
+ return write.map(() => newSsSecret);
133
+ })
134
+ .then(x => x.map(ssSecret => ({
135
+ ssSecret: ssSecret,
136
+ ssPublicKey: getSsPub(ssSecret),
137
+ })));
138
+ }
139
+ async function getEncrKeys(appId, secretStorage) {
140
+ return (await secretStorage.readEncrSecret())
141
+ .andThenPromise(async (encrSecret) => {
142
+ if (encrSecret) {
143
+ return ok(encrSecret);
144
+ }
145
+ const seed = createRandomSeed(appId, ENCR_SECRET_SEED_SIZE);
146
+ const newEncrSecret = createEncrSecret(seed);
147
+ const write = await secretStorage.writeEncrSecret(newEncrSecret);
148
+ return write.map(() => newEncrSecret);
149
+ })
150
+ .then(x => x.map(encrSecret => ({
151
+ encrSecret,
152
+ encrPublicKey: getEncrPub(encrSecret),
153
+ })));
154
+ }
149
155
  async function getSecretKeys(appId, secretStorage) {
150
- let ssSecret = await secretStorage.readSsSecret();
151
- if (!ssSecret) {
152
- // TODO randomize seed
153
- // For testing purpose only
154
- const seed = createStableSeed(appId, SS_SECRET_SEED_SIZE);
155
- ssSecret = createSsSecret(seed);
156
- await secretStorage.writeSsSecret(ssSecret);
157
- }
158
- let encrSecret = await secretStorage.readEncrSecret();
159
- if (!encrSecret) {
160
- // TODO randomize seed
161
- // For testing purpose only
162
- const seed = createStableSeed(appId, ENCR_SECRET_SEED_SIZE);
163
- encrSecret = createEncrSecret(seed);
164
- await secretStorage.writeEncrSecret(encrSecret);
165
- }
166
- const ssPublicKey = getSsPub(ssSecret);
167
- const encrPublicKey = getEncrPub(encrSecret);
168
- return { ssPublicKey, encrPublicKey, ssSecret, encrSecret };
156
+ return seq(await getSsKeys(appId, secretStorage), await getEncrKeys(appId, secretStorage)).map(([ss, encr]) => ({
157
+ ...ss,
158
+ ...encr,
159
+ }));
169
160
  }
170
161
  function createDeeplink(payload) {
171
162
  return `polkadotapp://pair?handshake=${toHex(payload)}`;
@@ -182,10 +173,16 @@ function waitForStatements(transport, topic, abortSignal, callback) {
182
173
  reject(e);
183
174
  }
184
175
  }
185
- callback(statements, value => {
176
+ try {
177
+ callback(statements, value => {
178
+ unsubscribe();
179
+ resolve(value);
180
+ });
181
+ }
182
+ catch (e) {
186
183
  unsubscribe();
187
- resolve(value);
188
- });
184
+ reject(e);
185
+ }
189
186
  });
190
187
  });
191
188
  }
@@ -0,0 +1,16 @@
1
+ type State<T> = ReturnType<typeof createState<T>>;
2
+ export declare function createState<T>(initial: T): {
3
+ read(): T;
4
+ write(value: T): T;
5
+ reset(): void;
6
+ subscribe(fn: (value: T) => void): () => void;
7
+ onFirstSubscribe(callback: VoidFunction): import("nanoevents").Unsubscribe;
8
+ onLastUnsubscribe(callback: VoidFunction): import("nanoevents").Unsubscribe;
9
+ };
10
+ export declare function readonly<T>(state: State<T>): {
11
+ read: () => T;
12
+ subscribe: (fn: (value: T) => void) => () => void;
13
+ onFirstSubscribe: (callback: VoidFunction) => import("nanoevents").Unsubscribe;
14
+ onLastUnsubscribe: (callback: VoidFunction) => import("nanoevents").Unsubscribe;
15
+ };
16
+ export {};
@@ -0,0 +1,50 @@
1
+ import { createNanoEvents } from 'nanoevents';
2
+ export function createState(initial) {
3
+ const events = createNanoEvents();
4
+ let currentValue = initial;
5
+ return {
6
+ read() {
7
+ return currentValue;
8
+ },
9
+ write(value) {
10
+ if (currentValue !== value) {
11
+ currentValue = value;
12
+ events.emit('value', value);
13
+ }
14
+ return value;
15
+ },
16
+ reset() {
17
+ if (currentValue !== initial) {
18
+ currentValue = initial;
19
+ events.emit('value', initial);
20
+ }
21
+ },
22
+ subscribe(fn) {
23
+ if (!events.events.value || events.events.value.length === 0) {
24
+ events.emit('first');
25
+ }
26
+ const unsubscribe = events.on('value', fn);
27
+ fn(currentValue);
28
+ return () => {
29
+ unsubscribe();
30
+ if (!events.events.value || events.events.value.length === 0) {
31
+ events.emit('last');
32
+ }
33
+ };
34
+ },
35
+ onFirstSubscribe(callback) {
36
+ return events.on('first', callback);
37
+ },
38
+ onLastUnsubscribe(callback) {
39
+ return events.on('last', callback);
40
+ },
41
+ };
42
+ }
43
+ export function readonly(state) {
44
+ return {
45
+ read: state.read,
46
+ subscribe: state.subscribe,
47
+ onFirstSubscribe: state.onFirstSubscribe,
48
+ onLastUnsubscribe: state.onLastUnsubscribe,
49
+ };
50
+ }
@@ -1,13 +1,12 @@
1
- import type { UnsignedStatement } from '@polkadot-api/sdk-statement';
1
+ import type { UserSession } from '../sso/session/ssoSessionStorage.js';
2
2
  import type { SsSecret } from './crypto.js';
3
- export declare function createSession({ sharedSecret, accountA, accountB, pinA, pinB, }: {
4
- sharedSecret: Uint8Array;
5
- accountA: Uint8Array;
6
- accountB: Uint8Array;
7
- pinA?: string;
8
- pinB?: string;
9
- }): {
10
- a: Uint8Array<ArrayBufferLike>;
11
- b: Uint8Array<ArrayBufferLike>;
3
+ import type { Account } from './session/types.js';
4
+ export declare function createUserSession(hostAccount: Account, peerAccount: Account): UserSession;
5
+ type StatementPayload = {
6
+ priority: number;
7
+ channel: Uint8Array;
8
+ topics: Uint8Array[];
9
+ data: Uint8Array;
12
10
  };
13
- export declare function createStatement(secret: SsSecret, payload: UnsignedStatement): Promise<import("@polkadot-api/sdk-statement").SignedStatement>;
11
+ export declare function createStatement(secret: SsSecret, payload: StatementPayload): import("neverthrow").ResultAsync<import("@polkadot-api/sdk-statement").SignedStatement, Error>;
12
+ export {};
@@ -1,20 +1,22 @@
1
1
  import { getStatementSigner } from '@polkadot-api/sdk-statement';
2
- import * as sr25519 from '@scure/sr25519';
3
- import { getSsPub, khash, mergeBytes, stringToBytes } from './crypto.js';
4
- export function createSession({ sharedSecret, accountA, accountB, pinA, pinB, }) {
5
- const sessionPrefix = stringToBytes('session');
6
- const pinSeparator = stringToBytes('/');
7
- function makePin(pin) {
8
- return pin ? mergeBytes(pinSeparator, stringToBytes(pin)) : pinSeparator;
9
- }
10
- const accountASessionParams = mergeBytes(sessionPrefix, accountA, accountB, makePin(pinA), makePin(pinB));
11
- const accountBSessionParams = mergeBytes(sessionPrefix, accountB, accountA, makePin(pinB), makePin(pinA));
2
+ import { Binary } from '@polkadot-api/substrate-bindings';
3
+ import { nanoid } from 'nanoid';
4
+ import { fromPromise } from 'neverthrow';
5
+ import { toError } from '../helpers/utils.js';
6
+ import { getSsPub, signWithSsSecret } from './crypto.js';
7
+ export function createUserSession(hostAccount, peerAccount) {
12
8
  return {
13
- a: khash(sharedSecret, accountASessionParams),
14
- b: khash(sharedSecret, accountBSessionParams),
9
+ id: nanoid(12),
10
+ peer: peerAccount,
11
+ host: hostAccount,
15
12
  };
16
13
  }
17
14
  export function createStatement(secret, payload) {
18
- const signer = getStatementSigner(getSsPub(secret), 'sr25519', data => sr25519.sign(secret, data));
19
- return signer.sign(payload);
15
+ const signer = getStatementSigner(getSsPub(secret), 'sr25519', data => signWithSsSecret(secret, data));
16
+ return fromPromise(signer.sign({
17
+ priority: payload.priority,
18
+ channel: Binary.fromBytes(payload.channel),
19
+ topics: payload.topics.map(Binary.fromBytes),
20
+ data: Binary.fromBytes(payload.data),
21
+ }), toError);
20
22
  }
@@ -0,0 +1,34 @@
1
+ import type { Statement } from '@polkadot-api/sdk-statement';
2
+ import type { StatementAdapter } from '../adapters/statement/types.js';
3
+ import type { StorageAdapter } from '../adapters/storage/types.js';
4
+ import type { Callback } from '../types.js';
5
+ import type { SsSecret } from './crypto.js';
6
+ export declare function createSession({ sharedSecret, accountA, accountB, pinA, pinB, }: {
7
+ sharedSecret: Uint8Array;
8
+ accountA: Uint8Array;
9
+ accountB: Uint8Array;
10
+ pinA?: string;
11
+ pinB?: string;
12
+ }): {
13
+ a: Uint8Array<ArrayBufferLike>;
14
+ b: Uint8Array<ArrayBufferLike>;
15
+ };
16
+ export declare function createRequestChannel(session: Uint8Array): Uint8Array<ArrayBufferLike>;
17
+ export declare function createResponseChannel(session: Uint8Array): Uint8Array<ArrayBufferLike>;
18
+ type StatementPayload = {
19
+ priority: number;
20
+ channel: Uint8Array;
21
+ topics: Uint8Array[];
22
+ data: Uint8Array;
23
+ };
24
+ export declare function createStatement(secret: SsSecret, payload: StatementPayload): Promise<import("@polkadot-api/sdk-statement").SignedStatement>;
25
+ type Params = {
26
+ topic: Uint8Array;
27
+ statement: StatementAdapter;
28
+ storage: StorageAdapter;
29
+ };
30
+ export declare function createStatementTopic({ topic, statement }: Params): {
31
+ subscribe(callback: Callback<Statement, boolean>): VoidFunction;
32
+ submit(): void;
33
+ };
34
+ export {};
@@ -0,0 +1,46 @@
1
+ import { getStatementSigner } from '@polkadot-api/sdk-statement';
2
+ import { Binary } from '@polkadot-api/substrate-bindings';
3
+ import { getSsPub, khash, mergeBytes, signWithSsSecret, stringToBytes } from './crypto.js';
4
+ export function createSession({ sharedSecret, accountA, accountB, pinA, pinB, }) {
5
+ const sessionPrefix = stringToBytes('session');
6
+ const pinSeparator = stringToBytes('/');
7
+ function makePin(pin) {
8
+ return pin ? mergeBytes(pinSeparator, stringToBytes(pin)) : pinSeparator;
9
+ }
10
+ const accountASessionParams = mergeBytes(sessionPrefix, accountA, accountB, makePin(pinA), makePin(pinB));
11
+ const accountBSessionParams = mergeBytes(sessionPrefix, accountB, accountA, makePin(pinB), makePin(pinA));
12
+ return {
13
+ a: khash(sharedSecret, accountASessionParams),
14
+ b: khash(sharedSecret, accountBSessionParams),
15
+ };
16
+ }
17
+ export function createRequestChannel(session) {
18
+ return khash(session, stringToBytes('request'));
19
+ }
20
+ export function createResponseChannel(session) {
21
+ return khash(session, stringToBytes('response'));
22
+ }
23
+ export function createStatement(secret, payload) {
24
+ const signer = getStatementSigner(getSsPub(secret), 'sr25519', data => signWithSsSecret(secret, data));
25
+ return signer.sign({
26
+ priority: payload.priority,
27
+ channel: Binary.fromBytes(payload.channel),
28
+ topics: payload.topics.map(Binary.fromBytes),
29
+ data: Binary.fromBytes(payload.data),
30
+ });
31
+ }
32
+ export function createStatementTopic({ topic, statement }) {
33
+ return {
34
+ subscribe(callback) {
35
+ return statement.subscribeStatements([topic], statements => {
36
+ for (const statement of statements) {
37
+ const processed = callback(statement);
38
+ if (processed) {
39
+ // TODO save anywhere
40
+ }
41
+ }
42
+ });
43
+ },
44
+ submit() { },
45
+ };
46
+ }
@@ -0,0 +1,25 @@
1
+ import type { ResultAsync } from 'neverthrow';
2
+ import type { StorageAdapter } from '../adapters/storage/types.js';
3
+ type Params<T> = {
4
+ storage: StorageAdapter;
5
+ key: string;
6
+ initial: T;
7
+ autosync?: boolean;
8
+ from(value: string): T;
9
+ to(value: T): string | null;
10
+ };
11
+ export declare function storageView<T>({ storage, initial, key, from, to, autosync }: Params<T>): {
12
+ read(): any;
13
+ write(value: T): any;
14
+ clear(): any;
15
+ subscribe(fn: (value: T) => void): () => void;
16
+ };
17
+ export declare function storageListView<T>(params: Params<T[]>): {
18
+ add(value: T): ResultAsync<T, Error>;
19
+ mutate(fn: (value: T[]) => T[]): ResultAsync<T[], Error>;
20
+ read(): any;
21
+ write(value: T[]): any;
22
+ clear(): any;
23
+ subscribe(fn: (value: T[]) => void): () => void;
24
+ };
25
+ export {};