@novasamatech/host-papp 0.5.0-9 → 0.5.0

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 (170) 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/generated.json +1 -0
  14. package/.papi/descriptors/package.json +24 -0
  15. package/.papi/metadata/people_lite.scale +0 -0
  16. package/.papi/polkadot-api.json +15 -0
  17. package/dist/constants.d.ts +2 -2
  18. package/dist/constants.js +2 -2
  19. package/dist/crypto.d.ts +11 -5
  20. package/dist/crypto.js +47 -11
  21. package/dist/helpers/abortError.d.ts +0 -1
  22. package/dist/helpers/abortError.js +0 -3
  23. package/dist/identity/rpcAdapter.js +13 -5
  24. package/dist/identity/types.d.ts +3 -4
  25. package/dist/index.d.ts +4 -1
  26. package/dist/index.js +1 -0
  27. package/dist/papp.js +3 -3
  28. package/dist/sso/auth/attestationService.d.ts +18 -0
  29. package/dist/sso/auth/attestationService.js +171 -0
  30. package/dist/sso/auth/impl.d.ts +36 -5
  31. package/dist/sso/auth/impl.js +94 -56
  32. package/dist/sso/auth/types.d.ts +15 -2
  33. package/dist/sso/sessionManager/scale/hex.d.ts +1 -0
  34. package/dist/sso/sessionManager/scale/hex.js +3 -0
  35. package/dist/sso/sessionManager/scale/remoteMessage.d.ts +30 -12
  36. package/dist/sso/sessionManager/scale/remoteMessage.js +10 -11
  37. package/dist/sso/sessionManager/scale/signPayloadRequest.d.ts +20 -0
  38. package/dist/sso/sessionManager/scale/signPayloadRequest.js +20 -0
  39. package/dist/sso/sessionManager/scale/signPayloadResponse.d.ts +14 -0
  40. package/dist/sso/sessionManager/scale/signPayloadResponse.js +10 -0
  41. package/dist/sso/sessionManager/userSession.d.ts +5 -7
  42. package/dist/sso/sessionManager/userSession.js +53 -12
  43. package/dist/sso/userSecretRepository.d.ts +1 -0
  44. package/dist/sso/userSecretRepository.js +2 -1
  45. package/dist/sso/userSessionRepository.js +0 -1
  46. package/package.json +12 -9
  47. package/dist/adapters/identity/rpc.d.ts +0 -6
  48. package/dist/adapters/identity/rpc.js +0 -101
  49. package/dist/adapters/identity/types.d.ts +0 -10
  50. package/dist/adapters/identity/types.js +0 -1
  51. package/dist/adapters/lazyClient/papi.d.ts +0 -3
  52. package/dist/adapters/lazyClient/papi.js +0 -17
  53. package/dist/adapters/lazyClient/types.d.ts +0 -5
  54. package/dist/adapters/lazyClient/types.js +0 -1
  55. package/dist/adapters/statement/rpc.d.ts +0 -3
  56. package/dist/adapters/statement/rpc.js +0 -93
  57. package/dist/adapters/statement/types.d.ts +0 -9
  58. package/dist/adapters/statement/types.js +0 -1
  59. package/dist/adapters/storage/localStorage.d.ts +0 -2
  60. package/dist/adapters/storage/localStorage.js +0 -34
  61. package/dist/adapters/storage/memory.d.ts +0 -2
  62. package/dist/adapters/storage/memory.js +0 -22
  63. package/dist/adapters/storage/types.d.ts +0 -7
  64. package/dist/adapters/storage/types.js +0 -1
  65. package/dist/adapters/transport/rpc.d.ts +0 -3
  66. package/dist/adapters/transport/rpc.js +0 -51
  67. package/dist/adapters/transport/types.d.ts +0 -6
  68. package/dist/adapters/transport/types.js +0 -1
  69. package/dist/components/auth/codec.d.ts +0 -9
  70. package/dist/components/auth/codec.js +0 -10
  71. package/dist/components/auth/codecs.d.ts +0 -9
  72. package/dist/components/auth/codecs.js +0 -10
  73. package/dist/components/auth/index.d.ts +0 -36
  74. package/dist/components/auth/index.js +0 -150
  75. package/dist/components/auth/types.d.ts +0 -15
  76. package/dist/components/auth/types.js +0 -1
  77. package/dist/components/session.d.ts +0 -34
  78. package/dist/components/session.js +0 -54
  79. package/dist/components/sso/index.d.ts +0 -36
  80. package/dist/components/sso/index.js +0 -150
  81. package/dist/components/sso/scale/handshake.d.ts +0 -9
  82. package/dist/components/sso/scale/handshake.js +0 -10
  83. package/dist/components/sso/types.d.ts +0 -15
  84. package/dist/components/sso/types.js +0 -1
  85. package/dist/components/transport.d.ts +0 -27
  86. package/dist/components/transport.js +0 -57
  87. package/dist/components/user/codec.d.ts +0 -16
  88. package/dist/components/user/codec.js +0 -13
  89. package/dist/components/user/index.d.ts +0 -22
  90. package/dist/components/user/index.js +0 -58
  91. package/dist/components/user/ssoMessageStream.d.ts +0 -10
  92. package/dist/components/user/ssoMessageStream.js +0 -8
  93. package/dist/components/user/ssoSession.d.ts +0 -5
  94. package/dist/components/user/ssoSession.js +0 -5
  95. package/dist/components/user/storage.d.ts +0 -27
  96. package/dist/components/user/storage.js +0 -143
  97. package/dist/components/user/types.d.ts +0 -6
  98. package/dist/components/user/types.js +0 -1
  99. package/dist/components/user/userSessionStorage.d.ts +0 -20
  100. package/dist/components/user/userSessionStorage.js +0 -24
  101. package/dist/components/user.d.ts +0 -74
  102. package/dist/components/user.js +0 -188
  103. package/dist/helpers/result.d.ts +0 -12
  104. package/dist/helpers/result.js +0 -15
  105. package/dist/helpers/result.spec.d.ts +0 -1
  106. package/dist/helpers/result.spec.js +0 -23
  107. package/dist/helpers.d.ts +0 -1
  108. package/dist/helpers.js +0 -3
  109. package/dist/modules/accounts.d.ts +0 -1
  110. package/dist/modules/accounts.js +0 -2
  111. package/dist/modules/crypto.d.ts +0 -23
  112. package/dist/modules/crypto.js +0 -51
  113. package/dist/modules/secretStorage.d.ts +0 -15
  114. package/dist/modules/secretStorage.js +0 -44
  115. package/dist/modules/session/helpers.d.ts +0 -5
  116. package/dist/modules/session/helpers.js +0 -29
  117. package/dist/modules/session/session.d.ts +0 -12
  118. package/dist/modules/session/session.js +0 -50
  119. package/dist/modules/session/types.d.ts +0 -12
  120. package/dist/modules/session/types.js +0 -1
  121. package/dist/modules/signIn.d.ts +0 -67
  122. package/dist/modules/signIn.js +0 -188
  123. package/dist/modules/state.d.ts +0 -16
  124. package/dist/modules/state.js +0 -50
  125. package/dist/modules/statementStore.d.ts +0 -12
  126. package/dist/modules/statementStore.js +0 -22
  127. package/dist/modules/statementTopic.d.ts +0 -34
  128. package/dist/modules/statementTopic.js +0 -46
  129. package/dist/modules/storageView.d.ts +0 -25
  130. package/dist/modules/storageView.js +0 -51
  131. package/dist/modules/syncStorage.d.ts +0 -25
  132. package/dist/modules/syncStorage.js +0 -76
  133. package/dist/modules/transport/codec.d.ts +0 -24
  134. package/dist/modules/transport/codec.js +0 -36
  135. package/dist/modules/transport/crypto.d.ts +0 -2
  136. package/dist/modules/transport/crypto.js +0 -20
  137. package/dist/modules/transport/transport.d.ts +0 -42
  138. package/dist/modules/transport/transport.js +0 -66
  139. package/dist/modules/user.d.ts +0 -67
  140. package/dist/modules/user.js +0 -188
  141. package/dist/modules/userManager.d.ts +0 -15
  142. package/dist/modules/userManager.js +0 -105
  143. package/dist/modules/userStorage.d.ts +0 -19
  144. package/dist/modules/userStorage.js +0 -108
  145. package/dist/modules/userStore.d.ts +0 -15
  146. package/dist/modules/userStore.js +0 -105
  147. package/dist/sso/session/impl.d.ts +0 -23
  148. package/dist/sso/session/impl.js +0 -57
  149. package/dist/sso/session/scale/remoteMessage.d.ts +0 -10
  150. package/dist/sso/session/scale/remoteMessage.js +0 -13
  151. package/dist/sso/session/sessionManager.d.ts +0 -23
  152. package/dist/sso/session/sessionManager.js +0 -58
  153. package/dist/sso/session/ssoSession.d.ts +0 -8
  154. package/dist/sso/session/ssoSession.js +0 -5
  155. package/dist/sso/session/ssoSessionStorage.d.ts +0 -21
  156. package/dist/sso/session/ssoSessionStorage.js +0 -20
  157. package/dist/sso/session/types.d.ts +0 -6
  158. package/dist/sso/session/types.js +0 -1
  159. package/dist/sso/session/userSessionStorage.d.ts +0 -21
  160. package/dist/sso/session/userSessionStorage.js +0 -20
  161. package/dist/sso/sessionManager/repository/ssoSessionRepository.d.ts +0 -22
  162. package/dist/sso/sessionManager/repository/ssoSessionRepository.js +0 -27
  163. package/dist/sso/sessionManager/ssoSession.d.ts +0 -23
  164. package/dist/sso/sessionManager/ssoSession.js +0 -69
  165. package/dist/sso/sessionManager/ssoSessionProver.d.ts +0 -4
  166. package/dist/sso/sessionManager/ssoSessionProver.js +0 -35
  167. package/dist/sso/ssoSessionRepository.d.ts +0 -18
  168. package/dist/sso/ssoSessionRepository.js +0 -27
  169. package/dist/structs.d.ts +0 -24
  170. package/dist/structs.js +0 -36
@@ -1,33 +1,57 @@
1
1
  import { createAccountId, createEncryption, createLocalSessionAccount, createRemoteSessionAccount, khash, } from '@novasamatech/statement-store';
2
2
  import { mergeUint8, toHex } from '@polkadot-api/utils';
3
+ import { generateMnemonic } from '@polkadot-labs/hdkd-helpers';
3
4
  import { Result, ResultAsync, err, fromPromise, fromThrowable, ok } from 'neverthrow';
4
- import { createEncrSecret, createSharedSecret, createSsHardDerivation, createSsSecret, getEncrPub, getSsPub, stringToBytes, } from '../../crypto.js';
5
+ import { createEncrSecret, createSharedSecret, deriveSr25519Account, getEncrPub, stringToBytes } from '../../crypto.js';
5
6
  import { AbortError } from '../../helpers/abortError.js';
6
7
  import { createState, readonly } from '../../helpers/state.js';
7
8
  import { toError } from '../../helpers/utils.js';
8
9
  import { createStoredUserSession } from '../userSessionRepository.js';
10
+ import { createAliceVerifier, createAttestationService } from './attestationService.js';
9
11
  import { HandshakeData, HandshakeResponsePayload, HandshakeResponseSensitiveData } from './scale/handshake.js';
10
- export function createAuth({ metadata, statementStore, ssoSessionRepository, userSecretRepository }) {
11
- const authStatus = createState({ step: 'none' });
12
- let authResults = null;
12
+ export function createAuth({ metadata, statementStore, ssoSessionRepository, userSecretRepository, lazyClient, }) {
13
+ const attestationStatus = createState({ step: 'none' });
14
+ const pairingStatus = createState({ step: 'none' });
15
+ let authResult = null;
13
16
  let abort = null;
14
- function handshake(signal) {
15
- return getSecretKeys()
17
+ function attestAccount(account, signal) {
18
+ const attestationService = createAttestationService(lazyClient);
19
+ const verifier = createAliceVerifier();
20
+ const username = attestationService.claimUsername();
21
+ attestationStatus.write({ step: 'attestation', username });
22
+ return attestationService
23
+ .grantVerifierAllowance(verifier)
24
+ .andThrough(() => processSignal(signal))
25
+ .andThen(() => attestationService.registerLitePerson(username, account, verifier))
26
+ .andThrough(() => processSignal(signal))
16
27
  .andTee(() => {
17
- authStatus.write({ step: 'initial' });
28
+ attestationStatus.write({ step: 'finished' });
18
29
  })
19
- .asyncAndThen(({ encrSecret, encrPublicKey, ssSecret, ssPublicKey }) => {
20
- const localAccount = createLocalSessionAccount(createAccountId(ssPublicKey));
21
- const handshakePayload = createHandshakePayloadV1({ ssPublicKey, encrPublicKey, metadata }).andTee(payload => authStatus.write({ step: 'pairing', payload: createDeeplink(payload) }));
22
- const pappResponse = handshakePayload
23
- .andThen(() => createHandshakeTopic(localAccount, encrPublicKey))
24
- .asyncAndThen(topic => waitForStatements(callback => statementStore.subscribeStatements([topic], callback), signal, (statements, resolve) => {
30
+ .orTee(e => {
31
+ if (!(e instanceof AbortError)) {
32
+ attestationStatus.write({ step: 'attestationError', message: e.message });
33
+ }
34
+ });
35
+ }
36
+ function handshake(account, signal) {
37
+ const localAccount = createLocalSessionAccount(createAccountId(account.publicKey));
38
+ pairingStatus.write({ step: 'initial' });
39
+ const encrKeys = createEncrKeys(account.entropy);
40
+ const handshakePayload = encrKeys.andThen(({ publicKey }) => createHandshakePayloadV1({
41
+ ssPublicKey: account.publicKey,
42
+ encrPublicKey: publicKey,
43
+ metadata,
44
+ }));
45
+ const handshakeTopic = encrKeys.andThen(({ publicKey }) => createHandshakeTopic(localAccount, publicKey));
46
+ const dataPrepared = Result.combine([handshakePayload, handshakeTopic, encrKeys]).andTee(([payload]) => pairingStatus.write({ step: 'pairing', payload: createDeeplink(payload) }));
47
+ return dataPrepared.asyncAndThen(([, handshakeTopic, encrKeys]) => {
48
+ const pappResponse = waitForStatements(callback => statementStore.subscribeStatements([handshakeTopic], callback), signal, (statements, resolve) => {
25
49
  for (const statement of statements) {
26
50
  if (!statement.data)
27
51
  continue;
28
52
  const session = retrieveSession({
29
53
  localAccount,
30
- encrSecret,
54
+ encrSecret: encrKeys.secret,
31
55
  payload: statement.data.asBytes(),
32
56
  }).unwrapOr(null);
33
57
  if (session) {
@@ -35,36 +59,57 @@ export function createAuth({ metadata, statementStore, ssoSessionRepository, use
35
59
  break;
36
60
  }
37
61
  }
38
- }));
39
- const secretesSaved = pappResponse.andThen(({ id }) => userSecretRepository.write(id, { ssSecret, encrSecret }));
62
+ });
63
+ const secretesSaved = pappResponse.andThen(({ id }) => {
64
+ return userSecretRepository.write(id, {
65
+ ssSecret: account.secret,
66
+ encrSecret: encrKeys.secret,
67
+ entropy: account.entropy,
68
+ });
69
+ });
70
+ // secrets and sso session should be chained, or it can produce an incorrect state
40
71
  const userCreated = secretesSaved.andThen(() => pappResponse.andThen(ssoSessionRepository.add));
41
- const result = ResultAsync.combine([userCreated, secretesSaved]).map(([session]) => session);
42
- return result
43
- .orElse(e => (AbortError.isAbortError(e) ? ok(null) : err(toError(e))))
72
+ const sessionReceived = ResultAsync.combine([userCreated, secretesSaved]).map(([session]) => session);
73
+ return sessionReceived
44
74
  .andTee(session => {
45
- authStatus.write(session ? { step: 'finished', session } : { step: 'none' });
75
+ pairingStatus.write(session ? { step: 'finished', session } : { step: 'none' });
46
76
  })
47
77
  .orTee(e => {
48
- authStatus.write({ step: 'error', message: e.message });
78
+ if (!(e instanceof AbortError)) {
79
+ pairingStatus.write({ step: 'pairingError', message: e.message });
80
+ }
49
81
  });
50
82
  });
51
83
  }
52
84
  const authModule = {
53
- status: readonly(authStatus),
85
+ pairingStatus: readonly(pairingStatus),
86
+ attestationStatus: readonly(attestationStatus),
54
87
  authenticate() {
55
- if (authResults) {
56
- return authResults;
88
+ if (authResult) {
89
+ return authResult;
57
90
  }
58
91
  abort = new AbortController();
59
- authResults = handshake(abort.signal);
60
- return authResults;
92
+ const account = deriveSr25519Account(generateMnemonic(), '//wallet//sso');
93
+ authResult = ResultAsync.combine([handshake(account, abort.signal), attestAccount(account, abort.signal)])
94
+ .map(([session]) => session)
95
+ .orElse(e => (e instanceof AbortError ? ok(null) : err(e)))
96
+ .andTee(() => {
97
+ abort = null;
98
+ })
99
+ .orTee(() => {
100
+ authResult = null;
101
+ abort = null;
102
+ });
103
+ return authResult;
61
104
  },
62
105
  abortAuthentication() {
63
106
  if (abort) {
64
- authResults = null;
65
- authStatus.reset();
66
107
  abort.abort(new AbortError('Aborted by user.'));
108
+ abort = null;
67
109
  }
110
+ authResult = null;
111
+ pairingStatus.reset();
112
+ attestationStatus.reset();
68
113
  },
69
114
  };
70
115
  return authModule;
@@ -86,6 +131,13 @@ function parseHandshakePayload(payload) {
86
131
  throw new Error('Unsupported handshake payload version');
87
132
  }
88
133
  }
134
+ const createEncrKeys = fromThrowable((entropy) => {
135
+ const secret = createEncrSecret(entropy);
136
+ return {
137
+ secret,
138
+ publicKey: getEncrPub(secret),
139
+ };
140
+ }, toError);
89
141
  function retrieveSession({ payload, encrSecret, localAccount, }) {
90
142
  const { encrypted, tmpKey } = parseHandshakePayload(payload);
91
143
  const symmetricKey = createSharedSecret(encrSecret, tmpKey);
@@ -98,40 +150,17 @@ function retrieveSession({ payload, encrSecret, localAccount, }) {
98
150
  return createStoredUserSession(localAccount, peerAccount);
99
151
  });
100
152
  }
101
- const getSsKeys = fromThrowable(() => {
102
- const ssSecret = createSsHardDerivation(createSsSecret(), '//wallet//sso');
103
- return {
104
- ssSecret: ssSecret,
105
- ssPublicKey: getSsPub(ssSecret),
106
- };
107
- }, toError);
108
- const getEncrKeys = fromThrowable(() => {
109
- const encrSecret = createEncrSecret();
110
- return {
111
- encrSecret,
112
- encrPublicKey: getEncrPub(encrSecret),
113
- };
114
- }, toError);
115
- function getSecretKeys() {
116
- return Result.combine([getSsKeys(), getEncrKeys()]).map(([ss, encr]) => ({
117
- ...ss,
118
- ...encr,
119
- }));
120
- }
121
153
  function createDeeplink(payload) {
122
154
  return `polkadotapp://pair?handshake=${toHex(payload)}`;
123
155
  }
124
- function waitForStatements(subscribe, abortSignal, callback) {
156
+ function waitForStatements(subscribe, signal, callback) {
125
157
  return fromPromise(new Promise((resolve, reject) => {
126
158
  const unsubscribe = subscribe(statements => {
127
- if (abortSignal?.aborted) {
159
+ const abortError = processSignal(signal).match(() => null, e => e);
160
+ if (abortError) {
128
161
  unsubscribe();
129
- try {
130
- abortSignal.throwIfAborted();
131
- }
132
- catch (e) {
133
- reject(e);
134
- }
162
+ reject(abortError);
163
+ return;
135
164
  }
136
165
  try {
137
166
  callback(statements, value => {
@@ -146,3 +175,12 @@ function waitForStatements(subscribe, abortSignal, callback) {
146
175
  });
147
176
  }), toError);
148
177
  }
178
+ function processSignal(signal) {
179
+ try {
180
+ signal.throwIfAborted();
181
+ return ok();
182
+ }
183
+ catch (e) {
184
+ return err(toError(e));
185
+ }
186
+ }
@@ -1,15 +1,28 @@
1
1
  import type { StoredUserSession } from '../userSessionRepository.js';
2
- export type AuthentificationStatus = {
2
+ export type PairingStatus = {
3
3
  step: 'none';
4
4
  } | {
5
5
  step: 'initial';
6
+ } | {
7
+ step: 'attestation';
6
8
  } | {
7
9
  step: 'pairing';
8
10
  payload: string;
9
11
  } | {
10
- step: 'error';
12
+ step: 'pairingError';
11
13
  message: string;
12
14
  } | {
13
15
  step: 'finished';
14
16
  session: StoredUserSession;
15
17
  };
18
+ export type AttestationStatus = {
19
+ step: 'none';
20
+ } | {
21
+ step: 'attestation';
22
+ username: string;
23
+ } | {
24
+ step: 'attestationError';
25
+ message: string;
26
+ } | {
27
+ step: 'finished';
28
+ };
@@ -0,0 +1 @@
1
+ export declare const hexCodec: import("scale-ts").Codec<`0x${string}`>;
@@ -0,0 +1,3 @@
1
+ import { fromHex, toHex } from '@polkadot-api/utils';
2
+ import { Bytes, enhanceCodec } from 'scale-ts';
3
+ export const hexCodec = enhanceCodec(Bytes(), fromHex, v => toHex(v));
@@ -1,13 +1,5 @@
1
- export declare const RemoteMessageDataCodec: import("scale-ts").Codec<{
2
- tag: "v1";
3
- value: {
4
- tag: "Disconnected";
5
- value: undefined;
6
- } | {
7
- tag: "SigningRequest";
8
- value: Uint8Array<ArrayBufferLike>;
9
- };
10
- }>;
1
+ import type { CodecType } from 'scale-ts';
2
+ export type RemoteMessage = CodecType<typeof RemoteMessageCodec>;
11
3
  export declare const RemoteMessageCodec: import("scale-ts").Codec<{
12
4
  messageId: string;
13
5
  data: {
@@ -16,8 +8,34 @@ export declare const RemoteMessageCodec: import("scale-ts").Codec<{
16
8
  tag: "Disconnected";
17
9
  value: undefined;
18
10
  } | {
19
- tag: "SigningRequest";
20
- value: Uint8Array<ArrayBufferLike>;
11
+ tag: "SignRequest";
12
+ value: {
13
+ address: string;
14
+ blockHash: `0x${string}`;
15
+ blockNumber: `0x${string}`;
16
+ era: `0x${string}`;
17
+ genesisHash: `0x${string}`;
18
+ method: `0x${string}`;
19
+ nonce: `0x${string}`;
20
+ specVersion: `0x${string}`;
21
+ tip: `0x${string}`;
22
+ transactionVersion: `0x${string}`;
23
+ signedExtensions: string[];
24
+ version: number;
25
+ assetId: `0x${string}` | undefined;
26
+ metadataHash: `0x${string}` | undefined;
27
+ mode: number | undefined;
28
+ withSignedTransaction: boolean | undefined;
29
+ };
30
+ } | {
31
+ tag: "SignResponse";
32
+ value: {
33
+ respondingTo: string;
34
+ payload: import("scale-ts").ResultPayload<{
35
+ signature: Uint8Array<ArrayBufferLike>;
36
+ signedTransaction: Uint8Array<ArrayBufferLike> | undefined;
37
+ }, string>;
38
+ };
21
39
  };
22
40
  };
23
41
  }>;
@@ -1,14 +1,13 @@
1
- import { Bytes, Enum, Struct, _void, str } from 'scale-ts';
2
- export const RemoteMessageDataCodec = Enum({
3
- v1: Enum({
4
- Disconnected: _void,
5
- // TODO implement
6
- SigningRequest: Bytes(),
7
- // TODO implement
8
- // SigningResponse: Bytes(),
9
- }),
10
- });
1
+ import { Enum, Struct, _void, str } from 'scale-ts';
2
+ import { SignPayloadRequestCodec } from './signPayloadRequest.js';
3
+ import { SignPayloadResponseCodec } from './signPayloadResponse.js';
11
4
  export const RemoteMessageCodec = Struct({
12
5
  messageId: str,
13
- data: RemoteMessageDataCodec,
6
+ data: Enum({
7
+ v1: Enum({
8
+ Disconnected: _void,
9
+ SignRequest: SignPayloadRequestCodec,
10
+ SignResponse: SignPayloadResponseCodec,
11
+ }),
12
+ }),
14
13
  });
@@ -0,0 +1,20 @@
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: `0x${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
+ metadataHash: `0x${string}` | undefined;
18
+ mode: number | undefined;
19
+ withSignedTransaction: boolean | undefined;
20
+ }>;
@@ -0,0 +1,20 @@
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: hexCodec,
10
+ nonce: hexCodec,
11
+ specVersion: hexCodec,
12
+ tip: hexCodec,
13
+ transactionVersion: hexCodec,
14
+ signedExtensions: Vector(str),
15
+ version: u32,
16
+ assetId: Option(hexCodec),
17
+ metadataHash: Option(hexCodec),
18
+ mode: Option(u32),
19
+ withSignedTransaction: Option(bool),
20
+ });
@@ -0,0 +1,14 @@
1
+ import type { CodecType } from 'scale-ts';
2
+ export type SignPayloadResponseData = CodecType<typeof SignPayloadResponseDataCodec>;
3
+ export declare const SignPayloadResponseDataCodec: import("scale-ts").Codec<{
4
+ signature: Uint8Array<ArrayBufferLike>;
5
+ signedTransaction: Uint8Array<ArrayBufferLike> | undefined;
6
+ }>;
7
+ export type SignPayloadResponse = CodecType<typeof SignPayloadResponseCodec>;
8
+ export declare const SignPayloadResponseCodec: import("scale-ts").Codec<{
9
+ respondingTo: string;
10
+ payload: import("scale-ts").ResultPayload<{
11
+ signature: Uint8Array<ArrayBufferLike>;
12
+ signedTransaction: Uint8Array<ArrayBufferLike> | undefined;
13
+ }, string>;
14
+ }>;
@@ -0,0 +1,10 @@
1
+ import { Bytes, Option, Result, Struct, str } from 'scale-ts';
2
+ export const SignPayloadResponseDataCodec = Struct({
3
+ signature: Bytes(),
4
+ signedTransaction: Option(Bytes()),
5
+ });
6
+ export const SignPayloadResponseCodec = Struct({
7
+ // referencing to RemoteMessage.messageId
8
+ respondingTo: str,
9
+ payload: Result(SignPayloadResponseDataCodec, str),
10
+ });
@@ -4,14 +4,12 @@ import { ResultAsync } from 'neverthrow';
4
4
  import type { CodecType } from 'scale-ts';
5
5
  import type { Callback } from '../../types.js';
6
6
  import type { StoredUserSession } from '../userSessionRepository.js';
7
- import { RemoteMessageCodec, RemoteMessageDataCodec } from './scale/remoteMessage.js';
7
+ import { RemoteMessageCodec } from './scale/remoteMessage.js';
8
+ import type { SignPayloadRequest } from './scale/signPayloadRequest.js';
9
+ import type { SignPayloadResponseData } from './scale/signPayloadResponse.js';
8
10
  export type UserSession = StoredUserSession & {
9
- request(message: CodecType<typeof RemoteMessageDataCodec>): ResultAsync<{
10
- requestId: string;
11
- }, Error>;
12
- sendDisconnectMessage(): ResultAsync<{
13
- requestId: string;
14
- }, Error>;
11
+ sendDisconnectMessage(): ResultAsync<void, Error>;
12
+ signPayload(payload: SignPayloadRequest): ResultAsync<SignPayloadResponseData, Error>;
15
13
  subscribe(callback: Callback<CodecType<typeof RemoteMessageCodec>, ResultAsync<boolean, Error>>): VoidFunction;
16
14
  dispose(): void;
17
15
  };
@@ -1,8 +1,10 @@
1
1
  import { createSession } from '@novasamatech/statement-store';
2
2
  import { fieldListView } from '@novasamatech/storage-adapter';
3
+ import { AccountId } from '@polkadot-api/substrate-bindings';
4
+ import { toHex } from '@polkadot-api/utils';
3
5
  import { nanoid } from 'nanoid';
4
- import { ResultAsync, okAsync } from 'neverthrow';
5
- import { RemoteMessageCodec, RemoteMessageDataCodec } from './scale/remoteMessage.js';
6
+ import { ResultAsync, err, errAsync, ok, okAsync } from 'neverthrow';
7
+ import { RemoteMessageCodec } from './scale/remoteMessage.js';
6
8
  export function createUserSession({ userSession, statementStore, encryption, storage, prover, }) {
7
9
  const session = createSession({
8
10
  localAccount: userSession.localAccount,
@@ -16,20 +18,58 @@ export function createUserSession({ userSession, statementStore, encryption, sto
16
18
  key: `sso_processed_${userSession.id}`,
17
19
  from: JSON.parse,
18
20
  to: JSON.stringify,
19
- initial: [],
20
21
  });
21
22
  return {
22
23
  id: userSession.id,
23
24
  localAccount: userSession.localAccount,
24
25
  remoteAccount: userSession.remoteAccount,
25
- request(message) {
26
- return session.submitRequest(RemoteMessageCodec, {
27
- messageId: nanoid(),
28
- data: message,
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
+ const responseFilter = (message) => {
43
+ return (message.data.tag === 'v1' &&
44
+ message.data.value.tag === 'SignResponse' &&
45
+ message.data.value.value.respondingTo === messageId);
46
+ };
47
+ return request
48
+ .andThen(() => session.waitForRequestMessage(RemoteMessageCodec, responseFilter))
49
+ .andThen(message => {
50
+ const { data } = message.payload;
51
+ switch (data.tag) {
52
+ case 'v1': {
53
+ switch (data.value.tag) {
54
+ case 'SignResponse':
55
+ if (data.value.value.payload.success) {
56
+ return ok(data.value.value.payload.value);
57
+ }
58
+ else {
59
+ return err(new Error(data.value.value.payload.value));
60
+ }
61
+ default:
62
+ return err(new Error(`Incorrect sign response: ${data.value.tag}`));
63
+ }
64
+ }
65
+ default:
66
+ return err(new Error(`Unsupported message version ${data.tag}`));
67
+ }
29
68
  });
30
69
  },
31
70
  sendDisconnectMessage() {
32
- return session.submitRequest(RemoteMessageCodec, {
71
+ return session
72
+ .submitRequestMessage(RemoteMessageCodec, {
33
73
  messageId: nanoid(),
34
74
  data: {
35
75
  tag: 'v1',
@@ -38,23 +78,24 @@ export function createUserSession({ userSession, statementStore, encryption, sto
38
78
  value: undefined,
39
79
  },
40
80
  },
41
- });
81
+ })
82
+ .map(() => undefined);
42
83
  },
43
84
  subscribe(callback) {
44
85
  return session.subscribe(RemoteMessageCodec, messages => {
45
86
  processedMessages.read().andThen(processed => {
46
87
  const results = messages.map(message => {
47
88
  if (message.type === 'request') {
48
- const isMessageProcessed = processed.includes(message.data.messageId);
89
+ const isMessageProcessed = processed.includes(message.payload.messageId);
49
90
  if (isMessageProcessed) {
50
91
  return okAsync({ processed: false });
51
92
  }
52
- return callback(message.data)
93
+ return callback(message.payload)
53
94
  .orTee(error => {
54
95
  console.error('Error while processing sso messsage:', error);
55
96
  })
56
97
  .orElse(() => okAsync(false))
57
- .map(processed => (processed ? { processed, message: message.data } : { processed }));
98
+ .map(processed => (processed ? { processed, message: message.payload } : { processed }));
58
99
  }
59
100
  return okAsync({ processed: false });
60
101
  });
@@ -6,6 +6,7 @@ type StoredUserSecrets = CodecType<typeof StoredUserSecretsCodec>;
6
6
  declare const StoredUserSecretsCodec: import("scale-ts").Codec<{
7
7
  ssSecret: SsSecret;
8
8
  encrSecret: EncrSecret;
9
+ entropy: Uint8Array<ArrayBufferLike>;
9
10
  }>;
10
11
  export type UserSecretRepository = ReturnType<typeof createUserSecretRepository>;
11
12
  export declare function createUserSecretRepository(salt: string, storage: StorageAdapter): {
@@ -2,12 +2,13 @@ import { gcm } from '@noble/ciphers/aes.js';
2
2
  import { blake2b } from '@noble/hashes/blake2.js';
3
3
  import { fromHex, toHex } from '@polkadot-api/utils';
4
4
  import { fromThrowable } from 'neverthrow';
5
- import { Struct } from 'scale-ts';
5
+ import { Bytes, Struct } from 'scale-ts';
6
6
  import { BrandedBytesCodec, stringToBytes } from '../crypto.js';
7
7
  import { toError } from '../helpers/utils.js';
8
8
  const StoredUserSecretsCodec = Struct({
9
9
  ssSecret: BrandedBytesCodec(),
10
10
  encrSecret: BrandedBytesCodec(),
11
+ entropy: Bytes(),
11
12
  });
12
13
  export function createUserSecretRepository(salt, storage) {
13
14
  const baseKey = 'UserSecrets';
@@ -20,7 +20,6 @@ export const createUserSessionRepository = (storage) => {
20
20
  return fieldListView({
21
21
  storage,
22
22
  key: 'SsoSessions',
23
- initial: [],
24
23
  from: x => codec.dec(fromHex(x)),
25
24
  to: x => toHex(codec.enc(x)),
26
25
  });
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@novasamatech/host-papp",
3
3
  "type": "module",
4
- "version": "0.5.0-9",
4
+ "version": "0.5.0",
5
5
  "description": "Polkadot app integration",
6
6
  "license": "Apache-2.0",
7
7
  "repository": {
@@ -21,22 +21,25 @@
21
21
  },
22
22
  "files": [
23
23
  "dist",
24
+ ".papi",
24
25
  "README.md"
25
26
  ],
26
27
  "dependencies": {
27
- "@novasamatech/host-api": "0.5.0-9",
28
- "@novasamatech/statement-store": "0.5.0-9",
29
- "@novasamatech/storage-adapter": "0.5.0-9",
30
- "@polkadot-api/substrate-bindings": "^0.16.5",
31
- "@scure/sr25519": "1.0.0",
28
+ "@noble/ciphers": "2.1.1",
32
29
  "@noble/curves": "2.0.1",
33
30
  "@noble/hashes": "2.0.1",
34
- "@noble/ciphers": "2.1.1",
35
- "polkadot-api": "^1.23.1",
31
+ "@novasamatech/host-api": "0.5.0",
32
+ "@novasamatech/statement-store": "0.5.0",
33
+ "@novasamatech/storage-adapter": "0.5.0",
34
+ "@polkadot-api/substrate-bindings": "^0.16.5",
35
+ "@polkadot-labs/hdkd-helpers": "^0.0.27",
36
+ "@scure/sr25519": "1.0.0",
36
37
  "nanoevents": "9.1.0",
37
38
  "nanoid": "5.1.6",
38
39
  "neverthrow": "^8.2.0",
39
- "scale-ts": "1.6.1"
40
+ "polkadot-api": "^1.23.2",
41
+ "scale-ts": "1.6.1",
42
+ "verifiablejs": "1.1.0"
40
43
  },
41
44
  "publishConfig": {
42
45
  "access": "public"
@@ -1,6 +0,0 @@
1
- import type { LazyClient } from '@novasamatech/statement-store';
2
- import type { StorageAdapter } from '@novasamatech/storage-adapter';
3
- import { ResultAsync } from 'neverthrow';
4
- import type { Identity, IdentityAdapter } from './types.js';
5
- export declare function createCachedIdentityRequester(storage: StorageAdapter, getKey: (accountId: string) => string, request: (accounts: string[]) => ResultAsync<(Identity | null)[], Error>): (accounts: string[]) => ResultAsync<Record<string, Identity | null>, Error>;
6
- export declare function createIdentityRpcAdapter(lazyClient: LazyClient, storage: StorageAdapter): IdentityAdapter;