@sneekin/sdk 1.1.0 → 1.1.1
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/dist/core/derive-keys.d.ts +1 -0
- package/dist/core/generated/api.d.ts +199 -245
- package/dist/index.cjs +31 -24
- package/dist/index.js +29 -23
- package/dist/messages/index.cjs +31 -24
- package/dist/messages/index.js +29 -23
- package/dist/pay/index.cjs +31 -24
- package/dist/pay/index.js +29 -23
- package/dist/verify/auth-schema.d.ts +2 -2
- package/dist/verify/index.cjs +34 -27
- package/dist/verify/index.js +32 -26
- package/package.json +1 -1
|
@@ -34,6 +34,56 @@ export type HealthResponse = {
|
|
|
34
34
|
timestamp: string;
|
|
35
35
|
service: string;
|
|
36
36
|
};
|
|
37
|
+
export type OpenapiDocumentResponse = {
|
|
38
|
+
[key: string]: unknown;
|
|
39
|
+
};
|
|
40
|
+
export type WebsiteSessionResponse = {
|
|
41
|
+
authenticated: true;
|
|
42
|
+
user: {
|
|
43
|
+
sub: string;
|
|
44
|
+
email: string;
|
|
45
|
+
displayName: string;
|
|
46
|
+
platformRole: 'owner' | 'admin' | 'developer' | 'viewer';
|
|
47
|
+
activeOrgId: string | null;
|
|
48
|
+
orgRoles: Array<{
|
|
49
|
+
orgId: string;
|
|
50
|
+
role: 'owner' | 'admin' | 'developer' | 'viewer';
|
|
51
|
+
}>;
|
|
52
|
+
};
|
|
53
|
+
} | {
|
|
54
|
+
authenticated: false;
|
|
55
|
+
user: null;
|
|
56
|
+
};
|
|
57
|
+
export type SneekVerifyAction = {
|
|
58
|
+
action: 'config';
|
|
59
|
+
} | {
|
|
60
|
+
action: 'request';
|
|
61
|
+
identifier: string;
|
|
62
|
+
} | {
|
|
63
|
+
action: 'switch';
|
|
64
|
+
requestId: string;
|
|
65
|
+
channel: 'sms' | 'whatsapp' | 'email' | 'push';
|
|
66
|
+
proof: string;
|
|
67
|
+
} | {
|
|
68
|
+
action: 'verify';
|
|
69
|
+
requestId: string;
|
|
70
|
+
code?: string;
|
|
71
|
+
proof: string;
|
|
72
|
+
} | {
|
|
73
|
+
action: 'verify';
|
|
74
|
+
requestId: string;
|
|
75
|
+
ref: string;
|
|
76
|
+
bindingProof: string;
|
|
77
|
+
} | {
|
|
78
|
+
action: 'create';
|
|
79
|
+
} | {
|
|
80
|
+
action: 'status';
|
|
81
|
+
ref: string;
|
|
82
|
+
bindingProof: string;
|
|
83
|
+
};
|
|
84
|
+
export type SneekVerifyResponse = {
|
|
85
|
+
[key: string]: unknown;
|
|
86
|
+
};
|
|
37
87
|
export type CreateApplication = {
|
|
38
88
|
websiteUrl: string;
|
|
39
89
|
displayName?: string;
|
|
@@ -53,7 +103,6 @@ export type UpdateApplication = {
|
|
|
53
103
|
};
|
|
54
104
|
export type CreateApiKey = {
|
|
55
105
|
name?: string;
|
|
56
|
-
environment?: 'live' | 'test';
|
|
57
106
|
expiresAt?: string;
|
|
58
107
|
};
|
|
59
108
|
export type ListApplicationsResponse = {
|
|
@@ -129,7 +178,6 @@ export type ListApiKeysResponse = {
|
|
|
129
178
|
applicationId: string;
|
|
130
179
|
name: string;
|
|
131
180
|
prefix: string;
|
|
132
|
-
environment: 'live' | 'test';
|
|
133
181
|
lastUsedAt: string | null;
|
|
134
182
|
expiresAt: string | null;
|
|
135
183
|
revokedAt: string | null;
|
|
@@ -141,7 +189,6 @@ export type CreateApiKeyResponse = {
|
|
|
141
189
|
applicationId: string;
|
|
142
190
|
name: string;
|
|
143
191
|
prefix: string;
|
|
144
|
-
environment: 'live' | 'test';
|
|
145
192
|
lastUsedAt: string | null;
|
|
146
193
|
expiresAt: string | null;
|
|
147
194
|
revokedAt: string | null;
|
|
@@ -149,16 +196,12 @@ export type CreateApiKeyResponse = {
|
|
|
149
196
|
key: string;
|
|
150
197
|
};
|
|
151
198
|
export type QrSignInSettings = {
|
|
152
|
-
secretCreatedAt: string | null;
|
|
153
199
|
webhookUrl: string | null;
|
|
154
200
|
defaultWebhookPath: string;
|
|
155
201
|
};
|
|
156
202
|
export type UpdateQrWebhook = {
|
|
157
203
|
webhookUrl: string | null;
|
|
158
204
|
};
|
|
159
|
-
export type CreateQrSigningSecretResponse = QrSignInSettings & {
|
|
160
|
-
secret: string;
|
|
161
|
-
};
|
|
162
205
|
export type CreateOrder = {
|
|
163
206
|
amount: string;
|
|
164
207
|
currency?: 'INR';
|
|
@@ -370,9 +413,6 @@ export type ListAuditLogResponse = {
|
|
|
370
413
|
organizationSlug: string | null;
|
|
371
414
|
}>;
|
|
372
415
|
};
|
|
373
|
-
export type GetOpenapiDocumentResponse = {
|
|
374
|
-
[key: string]: unknown;
|
|
375
|
-
};
|
|
376
416
|
export type OrganizationDetailResponse = {
|
|
377
417
|
organization: {
|
|
378
418
|
id: string;
|
|
@@ -422,6 +462,11 @@ export type OrganizationDetailResponse = {
|
|
|
422
462
|
analytics: {
|
|
423
463
|
currency: 'INR';
|
|
424
464
|
authUsers: number;
|
|
465
|
+
uniqueUsers: {
|
|
466
|
+
accounts: number;
|
|
467
|
+
emailOnly: number;
|
|
468
|
+
mobileOnly: number;
|
|
469
|
+
};
|
|
425
470
|
monthToDateChargeMicroInr: number;
|
|
426
471
|
allTimeChargeMicroInr: number;
|
|
427
472
|
monthToDateUsage: {
|
|
@@ -469,6 +514,11 @@ export type OrganizationDetailResponse = {
|
|
|
469
514
|
applicationAnalytics: Array<{
|
|
470
515
|
applicationId: string;
|
|
471
516
|
authUsers: number;
|
|
517
|
+
uniqueUsers: {
|
|
518
|
+
accounts: number;
|
|
519
|
+
emailOnly: number;
|
|
520
|
+
mobileOnly: number;
|
|
521
|
+
};
|
|
472
522
|
monthToDateChargeMicroInr: number;
|
|
473
523
|
monthToDateUsage: {
|
|
474
524
|
SMS_OTP: number;
|
|
@@ -613,6 +663,11 @@ export type ApplicationDetailResponse = {
|
|
|
613
663
|
analytics: {
|
|
614
664
|
currency: 'INR';
|
|
615
665
|
authUsers: number;
|
|
666
|
+
uniqueUsers: {
|
|
667
|
+
accounts: number;
|
|
668
|
+
emailOnly: number;
|
|
669
|
+
mobileOnly: number;
|
|
670
|
+
};
|
|
616
671
|
monthToDateChargeMicroInr: number;
|
|
617
672
|
allTimeChargeMicroInr: number;
|
|
618
673
|
monthToDateUsage: {
|
|
@@ -761,6 +816,11 @@ export type GetBillingResponse = {
|
|
|
761
816
|
analytics: {
|
|
762
817
|
currency: 'INR';
|
|
763
818
|
authUsers: number;
|
|
819
|
+
uniqueUsers: {
|
|
820
|
+
accounts: number;
|
|
821
|
+
emailOnly: number;
|
|
822
|
+
mobileOnly: number;
|
|
823
|
+
};
|
|
764
824
|
monthToDateChargeMicroInr: number;
|
|
765
825
|
allTimeChargeMicroInr: number;
|
|
766
826
|
monthToDateUsage: {
|
|
@@ -1012,12 +1072,29 @@ export type PushApprovalMatchResponse = {
|
|
|
1012
1072
|
trustedDeviceId: string;
|
|
1013
1073
|
algorithm: 'ES256';
|
|
1014
1074
|
};
|
|
1075
|
+
export type BeginPasskeyEnrollment = {
|
|
1076
|
+
publicKey: string;
|
|
1077
|
+
recoveryMode?: 'standard' | 'unavailable_device' | 'lost_all';
|
|
1078
|
+
};
|
|
1079
|
+
export type BeginPasskeyEnrollmentResponse = {
|
|
1080
|
+
challenge: string;
|
|
1081
|
+
algorithm: 'ES256';
|
|
1082
|
+
otpVerificationId: string;
|
|
1083
|
+
maskedIdentifier: string | null;
|
|
1084
|
+
expiresAt: string;
|
|
1085
|
+
approvalRequired: boolean;
|
|
1086
|
+
};
|
|
1015
1087
|
export type RegisterPasskey = {
|
|
1016
1088
|
response: {
|
|
1017
|
-
trustedDeviceId?: string;
|
|
1018
1089
|
publicKey: string;
|
|
1019
1090
|
signature: string;
|
|
1020
1091
|
};
|
|
1092
|
+
otpVerificationId: string;
|
|
1093
|
+
code: string;
|
|
1094
|
+
existingDeviceProof?: {
|
|
1095
|
+
trustedDeviceId: string;
|
|
1096
|
+
signature: string;
|
|
1097
|
+
};
|
|
1021
1098
|
label?: string;
|
|
1022
1099
|
};
|
|
1023
1100
|
export type DeviceCredentialOptions = {
|
|
@@ -1075,13 +1152,6 @@ export type RegisterPushTokenResponse = {
|
|
|
1075
1152
|
export type VerifyIdentifier = {
|
|
1076
1153
|
identifier: string;
|
|
1077
1154
|
};
|
|
1078
|
-
export type VerifyCode = {
|
|
1079
|
-
requestId: string;
|
|
1080
|
-
code?: string;
|
|
1081
|
-
response?: {
|
|
1082
|
-
[key: string]: unknown;
|
|
1083
|
-
};
|
|
1084
|
-
};
|
|
1085
1155
|
export type CheckVerification = {
|
|
1086
1156
|
code?: string;
|
|
1087
1157
|
response?: {
|
|
@@ -1106,14 +1176,9 @@ export type ApproveVerification = {
|
|
|
1106
1176
|
} | {
|
|
1107
1177
|
action: 'deny';
|
|
1108
1178
|
};
|
|
1109
|
-
export type InteractionQrResponse = {
|
|
1110
|
-
ref: string;
|
|
1111
|
-
nonce: string;
|
|
1112
|
-
issuedAt: number;
|
|
1113
|
-
expiresAt: number;
|
|
1114
|
-
};
|
|
1115
1179
|
export type ApproveQr = {
|
|
1116
1180
|
applicationId: string;
|
|
1181
|
+
kid?: string;
|
|
1117
1182
|
nonce: string;
|
|
1118
1183
|
origin: string;
|
|
1119
1184
|
iat: number;
|
|
@@ -1164,39 +1229,17 @@ export type VerifiedUser = {
|
|
|
1164
1229
|
profileUpdatedAt: string;
|
|
1165
1230
|
};
|
|
1166
1231
|
export type VerifyCheckResponse = {
|
|
1167
|
-
status: 'profile_required';
|
|
1168
|
-
profileComplete: false;
|
|
1169
|
-
profileEnrollmentUrl: string;
|
|
1170
|
-
} | {
|
|
1171
1232
|
status: 'verified';
|
|
1172
1233
|
idToken: string;
|
|
1173
1234
|
identifier: string;
|
|
1174
1235
|
kind: 'email' | 'mobile';
|
|
1175
|
-
} | {
|
|
1176
|
-
status: 'verified';
|
|
1177
|
-
idToken: string;
|
|
1178
|
-
subject: string;
|
|
1179
|
-
user: VerifiedUser;
|
|
1180
|
-
profileComplete: true;
|
|
1181
|
-
} | {
|
|
1182
|
-
status: 'verified';
|
|
1183
|
-
idToken: string;
|
|
1184
|
-
subject: string;
|
|
1185
|
-
user: VerifiedUser;
|
|
1186
|
-
profileComplete: true;
|
|
1187
|
-
accessToken: string;
|
|
1188
|
-
refreshToken: string;
|
|
1189
|
-
expiresIn: number;
|
|
1190
1236
|
};
|
|
1191
1237
|
export type VerifyApproveResponse = {
|
|
1192
1238
|
status: 'verified' | 'cancelled';
|
|
1193
1239
|
};
|
|
1194
|
-
export type QrConfigResponse = {
|
|
1195
|
-
applicationId: string;
|
|
1196
|
-
qrTtlSeconds: number;
|
|
1197
|
-
};
|
|
1198
1240
|
export type QrPartnerConfigResponse = {
|
|
1199
1241
|
applicationId: string;
|
|
1242
|
+
kid: string;
|
|
1200
1243
|
clientId: string;
|
|
1201
1244
|
issuer: string;
|
|
1202
1245
|
origins: Array<string>;
|
|
@@ -1211,26 +1254,6 @@ export type QrWebhookEvent = {
|
|
|
1211
1254
|
export type ApproveQrResponse = {
|
|
1212
1255
|
status: 'verified';
|
|
1213
1256
|
};
|
|
1214
|
-
export type InteractionIdentifierResponse = {
|
|
1215
|
-
requestId: string;
|
|
1216
|
-
channel?: 'sms' | 'whatsapp' | 'email' | 'push' | 'qr' | 'passkey';
|
|
1217
|
-
maskedIdentifier?: string;
|
|
1218
|
-
expiresAt?: string;
|
|
1219
|
-
instruction?: {
|
|
1220
|
-
code: 'approve_push' | 'enter_email_otp' | 'enter_whatsapp_otp' | 'enter_sms_otp';
|
|
1221
|
-
message: string;
|
|
1222
|
-
};
|
|
1223
|
-
alternatives?: Array<'sms' | 'whatsapp' | 'email' | 'push'>;
|
|
1224
|
-
challengeNumber?: string;
|
|
1225
|
-
publicKeyOptions?: {
|
|
1226
|
-
[key: string]: unknown;
|
|
1227
|
-
};
|
|
1228
|
-
};
|
|
1229
|
-
export type InteractionProfileRequiredResponse = {
|
|
1230
|
-
status: 'profile_required';
|
|
1231
|
-
profileComplete: false;
|
|
1232
|
-
profileEnrollmentUrl: string;
|
|
1233
|
-
};
|
|
1234
1257
|
export type UpdateProfile = {
|
|
1235
1258
|
displayName?: string;
|
|
1236
1259
|
addressLine1?: string;
|
|
@@ -1531,30 +1554,22 @@ export type ListOwnershipTransfersResponse = {
|
|
|
1531
1554
|
export type WhatsAppWebhookEvent = {
|
|
1532
1555
|
object?: string;
|
|
1533
1556
|
};
|
|
1534
|
-
export type
|
|
1535
|
-
|
|
1536
|
-
|
|
1537
|
-
|
|
1538
|
-
|
|
1539
|
-
|
|
1557
|
+
export type SigningJwk = {
|
|
1558
|
+
kty: 'EC';
|
|
1559
|
+
crv: 'P-256';
|
|
1560
|
+
x: string;
|
|
1561
|
+
y: string;
|
|
1562
|
+
kid: string;
|
|
1563
|
+
alg: 'ES256';
|
|
1564
|
+
use: 'sig';
|
|
1540
1565
|
};
|
|
1541
|
-
export type
|
|
1542
|
-
|
|
1543
|
-
user: {
|
|
1544
|
-
sub: string;
|
|
1545
|
-
email: string;
|
|
1546
|
-
displayName: string;
|
|
1547
|
-
platformRole: 'owner' | 'admin' | 'developer' | 'viewer';
|
|
1548
|
-
activeOrgId: string | null;
|
|
1549
|
-
orgRoles: Array<{
|
|
1550
|
-
orgId: string;
|
|
1551
|
-
role: 'owner' | 'admin' | 'developer' | 'viewer';
|
|
1552
|
-
}>;
|
|
1553
|
-
};
|
|
1554
|
-
profileEnrollmentUrl?: string;
|
|
1566
|
+
export type JwksResponse = {
|
|
1567
|
+
keys: Array<SigningJwk>;
|
|
1555
1568
|
};
|
|
1556
|
-
export type
|
|
1557
|
-
|
|
1569
|
+
export type OidcDiscoveryResponse = {
|
|
1570
|
+
issuer: string;
|
|
1571
|
+
jwks_uri: string;
|
|
1572
|
+
id_token_signing_alg_values_supported: Array<'ES256'>;
|
|
1558
1573
|
};
|
|
1559
1574
|
export type HealthGetData = {
|
|
1560
1575
|
body?: never;
|
|
@@ -1566,6 +1581,16 @@ export type HealthGetResponses = {
|
|
|
1566
1581
|
200: HealthResponse;
|
|
1567
1582
|
};
|
|
1568
1583
|
export type HealthGetResponse = HealthGetResponses[keyof HealthGetResponses];
|
|
1584
|
+
export type OpenapiGetPublicData = {
|
|
1585
|
+
body?: never;
|
|
1586
|
+
path?: never;
|
|
1587
|
+
query?: never;
|
|
1588
|
+
url: '/api/openapi.json';
|
|
1589
|
+
};
|
|
1590
|
+
export type OpenapiGetPublicResponses = {
|
|
1591
|
+
200: OpenapiDocumentResponse;
|
|
1592
|
+
};
|
|
1593
|
+
export type OpenapiGetPublicResponse = OpenapiGetPublicResponses[keyof OpenapiGetPublicResponses];
|
|
1569
1594
|
export type StorageGetData = {
|
|
1570
1595
|
body?: never;
|
|
1571
1596
|
path?: never;
|
|
@@ -1803,22 +1828,6 @@ export type VerifyApproveResponses = {
|
|
|
1803
1828
|
200: VerifyApproveResponse;
|
|
1804
1829
|
};
|
|
1805
1830
|
export type VerifyApproveResponse2 = VerifyApproveResponses[keyof VerifyApproveResponses];
|
|
1806
|
-
export type VerifyQrSubscribeData = {
|
|
1807
|
-
body?: never;
|
|
1808
|
-
path?: never;
|
|
1809
|
-
query: {
|
|
1810
|
-
ref: string;
|
|
1811
|
-
};
|
|
1812
|
-
url: '/api/verify/qr/subscribe';
|
|
1813
|
-
};
|
|
1814
|
-
export type VerifyQrSubscribeErrors = {
|
|
1815
|
-
400: ErrorEnvelope;
|
|
1816
|
-
};
|
|
1817
|
-
export type VerifyQrSubscribeError = VerifyQrSubscribeErrors[keyof VerifyQrSubscribeErrors];
|
|
1818
|
-
export type VerifyQrSubscribeResponses = {
|
|
1819
|
-
200: string;
|
|
1820
|
-
};
|
|
1821
|
-
export type VerifyQrSubscribeResponse = VerifyQrSubscribeResponses[keyof VerifyQrSubscribeResponses];
|
|
1822
1831
|
export type VerifyQrApproveData = {
|
|
1823
1832
|
body: ApproveQr;
|
|
1824
1833
|
path?: never;
|
|
@@ -1834,16 +1843,6 @@ export type VerifyQrApproveResponses = {
|
|
|
1834
1843
|
200: ApproveQrResponse;
|
|
1835
1844
|
};
|
|
1836
1845
|
export type VerifyQrApproveResponse = VerifyQrApproveResponses[keyof VerifyQrApproveResponses];
|
|
1837
|
-
export type VerifyQrConfigData = {
|
|
1838
|
-
body?: never;
|
|
1839
|
-
path?: never;
|
|
1840
|
-
query?: never;
|
|
1841
|
-
url: '/api/verify/qr/config';
|
|
1842
|
-
};
|
|
1843
|
-
export type VerifyQrConfigResponses = {
|
|
1844
|
-
200: QrConfigResponse;
|
|
1845
|
-
};
|
|
1846
|
-
export type VerifyQrConfigResponse = VerifyQrConfigResponses[keyof VerifyQrConfigResponses];
|
|
1847
1846
|
export type VerifyQrPartnerConfigData = {
|
|
1848
1847
|
body?: never;
|
|
1849
1848
|
path?: never;
|
|
@@ -1858,85 +1857,26 @@ export type VerifyQrPartnerConfigResponses = {
|
|
|
1858
1857
|
200: QrPartnerConfigResponse;
|
|
1859
1858
|
};
|
|
1860
1859
|
export type VerifyQrPartnerConfigResponse = VerifyQrPartnerConfigResponses[keyof VerifyQrPartnerConfigResponses];
|
|
1861
|
-
export type
|
|
1860
|
+
export type OidcJwksData = {
|
|
1862
1861
|
body?: never;
|
|
1863
|
-
path
|
|
1864
|
-
uid: string;
|
|
1865
|
-
};
|
|
1866
|
-
query?: never;
|
|
1867
|
-
url: '/interaction/{uid}/qr';
|
|
1868
|
-
};
|
|
1869
|
-
export type InteractionQrErrors = {
|
|
1870
|
-
400: ErrorEnvelope;
|
|
1871
|
-
};
|
|
1872
|
-
export type InteractionQrError = InteractionQrErrors[keyof InteractionQrErrors];
|
|
1873
|
-
export type InteractionQrResponses = {
|
|
1874
|
-
200: InteractionQrResponse;
|
|
1875
|
-
};
|
|
1876
|
-
export type InteractionQrResponse2 = InteractionQrResponses[keyof InteractionQrResponses];
|
|
1877
|
-
export type InteractionIdentifierData = {
|
|
1878
|
-
body: VerifyIdentifier;
|
|
1879
|
-
path: {
|
|
1880
|
-
uid: string;
|
|
1881
|
-
};
|
|
1882
|
-
query?: never;
|
|
1883
|
-
url: '/interaction/{uid}/identifier';
|
|
1884
|
-
};
|
|
1885
|
-
export type InteractionIdentifierErrors = {
|
|
1886
|
-
400: ErrorEnvelope;
|
|
1887
|
-
};
|
|
1888
|
-
export type InteractionIdentifierError = InteractionIdentifierErrors[keyof InteractionIdentifierErrors];
|
|
1889
|
-
export type InteractionIdentifierResponses = {
|
|
1890
|
-
200: InteractionIdentifierResponse;
|
|
1891
|
-
};
|
|
1892
|
-
export type InteractionIdentifierResponse2 = InteractionIdentifierResponses[keyof InteractionIdentifierResponses];
|
|
1893
|
-
export type InteractionVerifyData = {
|
|
1894
|
-
body: VerifyCode;
|
|
1895
|
-
path: {
|
|
1896
|
-
uid: string;
|
|
1897
|
-
};
|
|
1898
|
-
query?: never;
|
|
1899
|
-
url: '/interaction/{uid}/verify';
|
|
1900
|
-
};
|
|
1901
|
-
export type InteractionVerifyErrors = {
|
|
1902
|
-
400: ErrorEnvelope;
|
|
1903
|
-
};
|
|
1904
|
-
export type InteractionVerifyError = InteractionVerifyErrors[keyof InteractionVerifyErrors];
|
|
1905
|
-
export type InteractionVerifyResponses = {
|
|
1906
|
-
200: InteractionProfileRequiredResponse;
|
|
1907
|
-
};
|
|
1908
|
-
export type InteractionVerifyResponse = InteractionVerifyResponses[keyof InteractionVerifyResponses];
|
|
1909
|
-
export type InteractionSwitchMethodData = {
|
|
1910
|
-
body: SwitchVerificationMethod;
|
|
1911
|
-
path: {
|
|
1912
|
-
uid: string;
|
|
1913
|
-
id: string;
|
|
1914
|
-
};
|
|
1862
|
+
path?: never;
|
|
1915
1863
|
query?: never;
|
|
1916
|
-
url: '/
|
|
1917
|
-
};
|
|
1918
|
-
export type InteractionSwitchMethodErrors = {
|
|
1919
|
-
400: ErrorEnvelope;
|
|
1864
|
+
url: '/oauth/jwks';
|
|
1920
1865
|
};
|
|
1921
|
-
export type
|
|
1922
|
-
|
|
1923
|
-
200: InteractionIdentifierResponse;
|
|
1866
|
+
export type OidcJwksResponses = {
|
|
1867
|
+
200: JwksResponse;
|
|
1924
1868
|
};
|
|
1925
|
-
export type
|
|
1926
|
-
export type
|
|
1927
|
-
body
|
|
1869
|
+
export type OidcJwksResponse = OidcJwksResponses[keyof OidcJwksResponses];
|
|
1870
|
+
export type OidcDiscoveryData = {
|
|
1871
|
+
body?: never;
|
|
1928
1872
|
path?: never;
|
|
1929
1873
|
query?: never;
|
|
1930
|
-
url: '/
|
|
1874
|
+
url: '/.well-known/openid-configuration';
|
|
1931
1875
|
};
|
|
1932
|
-
export type
|
|
1933
|
-
|
|
1876
|
+
export type OidcDiscoveryResponses = {
|
|
1877
|
+
200: OidcDiscoveryResponse;
|
|
1934
1878
|
};
|
|
1935
|
-
export type
|
|
1936
|
-
export type OidcLogoutAllResponses = {
|
|
1937
|
-
200: OkResponse;
|
|
1938
|
-
};
|
|
1939
|
-
export type OidcLogoutAllResponse = OidcLogoutAllResponses[keyof OidcLogoutAllResponses];
|
|
1879
|
+
export type OidcDiscoveryResponse2 = OidcDiscoveryResponses[keyof OidcDiscoveryResponses];
|
|
1940
1880
|
export type FactorsListData = {
|
|
1941
1881
|
body?: never;
|
|
1942
1882
|
path?: never;
|
|
@@ -1981,17 +1921,18 @@ export type FactorsPendingApprovalsResponses = {
|
|
|
1981
1921
|
};
|
|
1982
1922
|
export type FactorsPendingApprovalsResponse = FactorsPendingApprovalsResponses[keyof FactorsPendingApprovalsResponses];
|
|
1983
1923
|
export type FactorsRegistrationOptionsData = {
|
|
1984
|
-
body
|
|
1924
|
+
body: BeginPasskeyEnrollment;
|
|
1985
1925
|
path?: never;
|
|
1986
1926
|
query?: never;
|
|
1987
1927
|
url: '/api/verify/factors/registration-options';
|
|
1988
1928
|
};
|
|
1989
1929
|
export type FactorsRegistrationOptionsErrors = {
|
|
1930
|
+
400: ErrorEnvelope;
|
|
1990
1931
|
401: ErrorEnvelope;
|
|
1991
1932
|
};
|
|
1992
1933
|
export type FactorsRegistrationOptionsError = FactorsRegistrationOptionsErrors[keyof FactorsRegistrationOptionsErrors];
|
|
1993
1934
|
export type FactorsRegistrationOptionsResponses = {
|
|
1994
|
-
200:
|
|
1935
|
+
200: BeginPasskeyEnrollmentResponse;
|
|
1995
1936
|
};
|
|
1996
1937
|
export type FactorsRegistrationOptionsResponse = FactorsRegistrationOptionsResponses[keyof FactorsRegistrationOptionsResponses];
|
|
1997
1938
|
export type FactorsAuthenticationOptionsData = {
|
|
@@ -2072,6 +2013,74 @@ export type FactorsRegisterPushTokenResponses = {
|
|
|
2072
2013
|
200: RegisterPushTokenResponse;
|
|
2073
2014
|
};
|
|
2074
2015
|
export type FactorsRegisterPushTokenResponse = FactorsRegisterPushTokenResponses[keyof FactorsRegisterPushTokenResponses];
|
|
2016
|
+
export type AuthSessionData = {
|
|
2017
|
+
body?: never;
|
|
2018
|
+
path?: never;
|
|
2019
|
+
query?: never;
|
|
2020
|
+
url: '/api/auth/session';
|
|
2021
|
+
};
|
|
2022
|
+
export type AuthSessionResponses = {
|
|
2023
|
+
200: WebsiteSessionResponse;
|
|
2024
|
+
};
|
|
2025
|
+
export type AuthSessionResponse = AuthSessionResponses[keyof AuthSessionResponses];
|
|
2026
|
+
export type AuthLogoutData = {
|
|
2027
|
+
body?: never;
|
|
2028
|
+
path?: never;
|
|
2029
|
+
query?: never;
|
|
2030
|
+
url: '/api/auth/logout';
|
|
2031
|
+
};
|
|
2032
|
+
export type AuthLogoutErrors = {
|
|
2033
|
+
401: ErrorEnvelope;
|
|
2034
|
+
403: ErrorEnvelope;
|
|
2035
|
+
};
|
|
2036
|
+
export type AuthLogoutError = AuthLogoutErrors[keyof AuthLogoutErrors];
|
|
2037
|
+
export type AuthLogoutResponses = {
|
|
2038
|
+
200: OkResponse;
|
|
2039
|
+
};
|
|
2040
|
+
export type AuthLogoutResponse = AuthLogoutResponses[keyof AuthLogoutResponses];
|
|
2041
|
+
export type AuthLogoutAllData = {
|
|
2042
|
+
body?: never;
|
|
2043
|
+
path?: never;
|
|
2044
|
+
query?: never;
|
|
2045
|
+
url: '/api/auth/logout-all';
|
|
2046
|
+
};
|
|
2047
|
+
export type AuthLogoutAllErrors = {
|
|
2048
|
+
401: ErrorEnvelope;
|
|
2049
|
+
403: ErrorEnvelope;
|
|
2050
|
+
};
|
|
2051
|
+
export type AuthLogoutAllError = AuthLogoutAllErrors[keyof AuthLogoutAllErrors];
|
|
2052
|
+
export type AuthLogoutAllResponses = {
|
|
2053
|
+
200: OkResponse;
|
|
2054
|
+
};
|
|
2055
|
+
export type AuthLogoutAllResponse = AuthLogoutAllResponses[keyof AuthLogoutAllResponses];
|
|
2056
|
+
export type AuthSneekData = {
|
|
2057
|
+
body: SneekVerifyAction;
|
|
2058
|
+
path?: never;
|
|
2059
|
+
query?: never;
|
|
2060
|
+
url: '/api/auth/sneek';
|
|
2061
|
+
};
|
|
2062
|
+
export type AuthSneekErrors = {
|
|
2063
|
+
400: ErrorEnvelope;
|
|
2064
|
+
};
|
|
2065
|
+
export type AuthSneekError = AuthSneekErrors[keyof AuthSneekErrors];
|
|
2066
|
+
export type AuthSneekResponses = {
|
|
2067
|
+
200: SneekVerifyResponse;
|
|
2068
|
+
};
|
|
2069
|
+
export type AuthSneekResponse = AuthSneekResponses[keyof AuthSneekResponses];
|
|
2070
|
+
export type AuthSneekWebhookData = {
|
|
2071
|
+
body: QrWebhookEvent;
|
|
2072
|
+
path?: never;
|
|
2073
|
+
query?: never;
|
|
2074
|
+
url: '/api/auth/sneek/webhook';
|
|
2075
|
+
};
|
|
2076
|
+
export type AuthSneekWebhookErrors = {
|
|
2077
|
+
400: ErrorEnvelope;
|
|
2078
|
+
};
|
|
2079
|
+
export type AuthSneekWebhookError = AuthSneekWebhookErrors[keyof AuthSneekWebhookErrors];
|
|
2080
|
+
export type AuthSneekWebhookResponses = {
|
|
2081
|
+
204: void;
|
|
2082
|
+
};
|
|
2083
|
+
export type AuthSneekWebhookResponse = AuthSneekWebhookResponses[keyof AuthSneekWebhookResponses];
|
|
2075
2084
|
export type AccountDeleteData = {
|
|
2076
2085
|
body?: never;
|
|
2077
2086
|
path?: never;
|
|
@@ -2760,24 +2769,6 @@ export type QrSignInGetResponses = {
|
|
|
2760
2769
|
200: QrSignInSettings;
|
|
2761
2770
|
};
|
|
2762
2771
|
export type QrSignInGetResponse = QrSignInGetResponses[keyof QrSignInGetResponses];
|
|
2763
|
-
export type QrSignInCreateSecretData = {
|
|
2764
|
-
body?: never;
|
|
2765
|
-
path: {
|
|
2766
|
-
orgId: string;
|
|
2767
|
-
appId: string;
|
|
2768
|
-
};
|
|
2769
|
-
query?: never;
|
|
2770
|
-
url: '/api/orgs/{orgId}/applications/{appId}/qr-sign-in/secret';
|
|
2771
|
-
};
|
|
2772
|
-
export type QrSignInCreateSecretErrors = {
|
|
2773
|
-
400: ErrorEnvelope;
|
|
2774
|
-
401: ErrorEnvelope;
|
|
2775
|
-
};
|
|
2776
|
-
export type QrSignInCreateSecretError = QrSignInCreateSecretErrors[keyof QrSignInCreateSecretErrors];
|
|
2777
|
-
export type QrSignInCreateSecretResponses = {
|
|
2778
|
-
201: CreateQrSigningSecretResponse;
|
|
2779
|
-
};
|
|
2780
|
-
export type QrSignInCreateSecretResponse = QrSignInCreateSecretResponses[keyof QrSignInCreateSecretResponses];
|
|
2781
2772
|
export type QrSignInUpdateWebhookData = {
|
|
2782
2773
|
body: UpdateQrWebhook;
|
|
2783
2774
|
path: {
|
|
@@ -2986,14 +2977,14 @@ export type ConsoleGetOpenapiData = {
|
|
|
2986
2977
|
body?: never;
|
|
2987
2978
|
path?: never;
|
|
2988
2979
|
query?: never;
|
|
2989
|
-
url: '/api/console/openapi';
|
|
2980
|
+
url: '/api/console/openapi.json';
|
|
2990
2981
|
};
|
|
2991
2982
|
export type ConsoleGetOpenapiErrors = {
|
|
2992
2983
|
401: ErrorEnvelope;
|
|
2993
2984
|
};
|
|
2994
2985
|
export type ConsoleGetOpenapiError = ConsoleGetOpenapiErrors[keyof ConsoleGetOpenapiErrors];
|
|
2995
2986
|
export type ConsoleGetOpenapiResponses = {
|
|
2996
|
-
200:
|
|
2987
|
+
200: OpenapiDocumentResponse;
|
|
2997
2988
|
};
|
|
2998
2989
|
export type ConsoleGetOpenapiResponse = ConsoleGetOpenapiResponses[keyof ConsoleGetOpenapiResponses];
|
|
2999
2990
|
export type ConsoleGetOrganizationData = {
|
|
@@ -3451,40 +3442,3 @@ export type WhatsappWebhookError = WhatsappWebhookErrors[keyof WhatsappWebhookEr
|
|
|
3451
3442
|
export type WhatsappWebhookResponses = {
|
|
3452
3443
|
200: unknown;
|
|
3453
3444
|
};
|
|
3454
|
-
export type WebAuthLoginData = {
|
|
3455
|
-
body?: never;
|
|
3456
|
-
path?: never;
|
|
3457
|
-
query?: never;
|
|
3458
|
-
url: '/api/auth/login';
|
|
3459
|
-
};
|
|
3460
|
-
export type WebAuthCallbackData = {
|
|
3461
|
-
body?: never;
|
|
3462
|
-
path?: never;
|
|
3463
|
-
query?: never;
|
|
3464
|
-
url: '/api/auth/callback';
|
|
3465
|
-
};
|
|
3466
|
-
export type WebAuthRefreshData = {
|
|
3467
|
-
body?: never;
|
|
3468
|
-
path?: never;
|
|
3469
|
-
query?: never;
|
|
3470
|
-
url: '/api/auth/refresh';
|
|
3471
|
-
};
|
|
3472
|
-
export type WebAuthRefreshErrors = {
|
|
3473
|
-
401: WebAuthSessionError;
|
|
3474
|
-
503: WebAuthSessionError;
|
|
3475
|
-
};
|
|
3476
|
-
export type WebAuthRefreshError = WebAuthRefreshErrors[keyof WebAuthRefreshErrors];
|
|
3477
|
-
export type WebAuthRefreshResponses = {
|
|
3478
|
-
200: WebAuthRefreshResponse;
|
|
3479
|
-
};
|
|
3480
|
-
export type WebAuthRefreshResponse2 = WebAuthRefreshResponses[keyof WebAuthRefreshResponses];
|
|
3481
|
-
export type WebAuthLogoutData = {
|
|
3482
|
-
body?: never;
|
|
3483
|
-
path?: never;
|
|
3484
|
-
query?: never;
|
|
3485
|
-
url: '/api/auth/logout';
|
|
3486
|
-
};
|
|
3487
|
-
export type WebAuthLogoutResponses = {
|
|
3488
|
-
200: OkResponse;
|
|
3489
|
-
};
|
|
3490
|
-
export type WebAuthLogoutResponse = WebAuthLogoutResponses[keyof WebAuthLogoutResponses];
|
package/dist/index.cjs
CHANGED
|
@@ -24,10 +24,37 @@ __export(src_exports, {
|
|
|
24
24
|
SneekApiError: () => SneekApiError,
|
|
25
25
|
SneekClient: () => SneekClient,
|
|
26
26
|
SneekPayClient: () => SneekPayClient,
|
|
27
|
-
deriveKeys: () => deriveKeys
|
|
27
|
+
deriveKeys: () => deriveKeys,
|
|
28
|
+
isValidApiKey: () => isValidApiKey
|
|
28
29
|
});
|
|
29
30
|
module.exports = __toCommonJS(src_exports);
|
|
30
31
|
|
|
32
|
+
// src/core/derive-keys.ts
|
|
33
|
+
var import_node_crypto = require("crypto");
|
|
34
|
+
var KEY_LABELS = {
|
|
35
|
+
qrSigningKey: "sneek-qr-v1",
|
|
36
|
+
webhookSigningKey: "sneek-webhook-v1",
|
|
37
|
+
proofKey: "sneek-proof-v1"
|
|
38
|
+
};
|
|
39
|
+
var API_KEY_PATTERN = /^sneek_[A-Za-z0-9_-]{43}$/;
|
|
40
|
+
function isValidApiKey(apiKey) {
|
|
41
|
+
return API_KEY_PATTERN.test(apiKey);
|
|
42
|
+
}
|
|
43
|
+
function deriveKeys(apiKey) {
|
|
44
|
+
if (typeof apiKey !== "string" || !isValidApiKey(apiKey)) {
|
|
45
|
+
throw new TypeError("apiKey must use the sneek_ format with a 43-character secret");
|
|
46
|
+
}
|
|
47
|
+
const inputKeyMaterial = Buffer.from(apiKey, "utf8");
|
|
48
|
+
const derive = (label) => Buffer.from(
|
|
49
|
+
(0, import_node_crypto.hkdfSync)("sha256", inputKeyMaterial, Buffer.alloc(0), label, 32)
|
|
50
|
+
);
|
|
51
|
+
return {
|
|
52
|
+
qrSigningKey: derive(KEY_LABELS.qrSigningKey),
|
|
53
|
+
webhookSigningKey: derive(KEY_LABELS.webhookSigningKey),
|
|
54
|
+
proofKey: derive(KEY_LABELS.proofKey)
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
|
|
31
58
|
// src/core/client.ts
|
|
32
59
|
var SneekApiError = class extends Error {
|
|
33
60
|
constructor(status, type, title, detail) {
|
|
@@ -52,6 +79,7 @@ var SneekClient = class {
|
|
|
52
79
|
constructor(options) {
|
|
53
80
|
if (!options.apiUrl) throw new Error("apiUrl is required");
|
|
54
81
|
if (!options.apiKey) throw new Error("apiKey is required");
|
|
82
|
+
if (!isValidApiKey(options.apiKey)) throw new Error("apiKey must use the sneek_ format with a 43-character secret");
|
|
55
83
|
this.apiUrl = options.apiUrl.replace(/\/+$/, "");
|
|
56
84
|
this.apiKey = options.apiKey;
|
|
57
85
|
this.fetchImpl = options.fetch ?? fetch;
|
|
@@ -123,28 +151,6 @@ function asProblem(value) {
|
|
|
123
151
|
};
|
|
124
152
|
}
|
|
125
153
|
|
|
126
|
-
// src/core/derive-keys.ts
|
|
127
|
-
var import_node_crypto = require("crypto");
|
|
128
|
-
var KEY_LABELS = {
|
|
129
|
-
qrSigningKey: "sneek-qr-v1",
|
|
130
|
-
webhookSigningKey: "sneek-webhook-v1",
|
|
131
|
-
proofKey: "sneek-proof-v1"
|
|
132
|
-
};
|
|
133
|
-
function deriveKeys(apiKey) {
|
|
134
|
-
if (typeof apiKey !== "string" || apiKey.length === 0) {
|
|
135
|
-
throw new TypeError("apiKey must be a nonempty string");
|
|
136
|
-
}
|
|
137
|
-
const inputKeyMaterial = Buffer.from(apiKey, "utf8");
|
|
138
|
-
const derive = (label) => Buffer.from(
|
|
139
|
-
(0, import_node_crypto.hkdfSync)("sha256", inputKeyMaterial, Buffer.alloc(0), label, 32)
|
|
140
|
-
);
|
|
141
|
-
return {
|
|
142
|
-
qrSigningKey: derive(KEY_LABELS.qrSigningKey),
|
|
143
|
-
webhookSigningKey: derive(KEY_LABELS.webhookSigningKey),
|
|
144
|
-
proofKey: derive(KEY_LABELS.proofKey)
|
|
145
|
-
};
|
|
146
|
-
}
|
|
147
|
-
|
|
148
154
|
// src/pay/payments.ts
|
|
149
155
|
var SneekPayClient = class {
|
|
150
156
|
client;
|
|
@@ -219,5 +225,6 @@ var OrdersClient = class {
|
|
|
219
225
|
SneekApiError,
|
|
220
226
|
SneekClient,
|
|
221
227
|
SneekPayClient,
|
|
222
|
-
deriveKeys
|
|
228
|
+
deriveKeys,
|
|
229
|
+
isValidApiKey
|
|
223
230
|
});
|
package/dist/index.js
CHANGED
|
@@ -1,3 +1,29 @@
|
|
|
1
|
+
// src/core/derive-keys.ts
|
|
2
|
+
import { hkdfSync } from "crypto";
|
|
3
|
+
var KEY_LABELS = {
|
|
4
|
+
qrSigningKey: "sneek-qr-v1",
|
|
5
|
+
webhookSigningKey: "sneek-webhook-v1",
|
|
6
|
+
proofKey: "sneek-proof-v1"
|
|
7
|
+
};
|
|
8
|
+
var API_KEY_PATTERN = /^sneek_[A-Za-z0-9_-]{43}$/;
|
|
9
|
+
function isValidApiKey(apiKey) {
|
|
10
|
+
return API_KEY_PATTERN.test(apiKey);
|
|
11
|
+
}
|
|
12
|
+
function deriveKeys(apiKey) {
|
|
13
|
+
if (typeof apiKey !== "string" || !isValidApiKey(apiKey)) {
|
|
14
|
+
throw new TypeError("apiKey must use the sneek_ format with a 43-character secret");
|
|
15
|
+
}
|
|
16
|
+
const inputKeyMaterial = Buffer.from(apiKey, "utf8");
|
|
17
|
+
const derive = (label) => Buffer.from(
|
|
18
|
+
hkdfSync("sha256", inputKeyMaterial, Buffer.alloc(0), label, 32)
|
|
19
|
+
);
|
|
20
|
+
return {
|
|
21
|
+
qrSigningKey: derive(KEY_LABELS.qrSigningKey),
|
|
22
|
+
webhookSigningKey: derive(KEY_LABELS.webhookSigningKey),
|
|
23
|
+
proofKey: derive(KEY_LABELS.proofKey)
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
|
|
1
27
|
// src/core/client.ts
|
|
2
28
|
var SneekApiError = class extends Error {
|
|
3
29
|
constructor(status, type, title, detail) {
|
|
@@ -22,6 +48,7 @@ var SneekClient = class {
|
|
|
22
48
|
constructor(options) {
|
|
23
49
|
if (!options.apiUrl) throw new Error("apiUrl is required");
|
|
24
50
|
if (!options.apiKey) throw new Error("apiKey is required");
|
|
51
|
+
if (!isValidApiKey(options.apiKey)) throw new Error("apiKey must use the sneek_ format with a 43-character secret");
|
|
25
52
|
this.apiUrl = options.apiUrl.replace(/\/+$/, "");
|
|
26
53
|
this.apiKey = options.apiKey;
|
|
27
54
|
this.fetchImpl = options.fetch ?? fetch;
|
|
@@ -93,28 +120,6 @@ function asProblem(value) {
|
|
|
93
120
|
};
|
|
94
121
|
}
|
|
95
122
|
|
|
96
|
-
// src/core/derive-keys.ts
|
|
97
|
-
import { hkdfSync } from "crypto";
|
|
98
|
-
var KEY_LABELS = {
|
|
99
|
-
qrSigningKey: "sneek-qr-v1",
|
|
100
|
-
webhookSigningKey: "sneek-webhook-v1",
|
|
101
|
-
proofKey: "sneek-proof-v1"
|
|
102
|
-
};
|
|
103
|
-
function deriveKeys(apiKey) {
|
|
104
|
-
if (typeof apiKey !== "string" || apiKey.length === 0) {
|
|
105
|
-
throw new TypeError("apiKey must be a nonempty string");
|
|
106
|
-
}
|
|
107
|
-
const inputKeyMaterial = Buffer.from(apiKey, "utf8");
|
|
108
|
-
const derive = (label) => Buffer.from(
|
|
109
|
-
hkdfSync("sha256", inputKeyMaterial, Buffer.alloc(0), label, 32)
|
|
110
|
-
);
|
|
111
|
-
return {
|
|
112
|
-
qrSigningKey: derive(KEY_LABELS.qrSigningKey),
|
|
113
|
-
webhookSigningKey: derive(KEY_LABELS.webhookSigningKey),
|
|
114
|
-
proofKey: derive(KEY_LABELS.proofKey)
|
|
115
|
-
};
|
|
116
|
-
}
|
|
117
|
-
|
|
118
123
|
// src/pay/payments.ts
|
|
119
124
|
var SneekPayClient = class {
|
|
120
125
|
client;
|
|
@@ -188,5 +193,6 @@ export {
|
|
|
188
193
|
SneekApiError,
|
|
189
194
|
SneekClient,
|
|
190
195
|
SneekPayClient,
|
|
191
|
-
deriveKeys
|
|
196
|
+
deriveKeys,
|
|
197
|
+
isValidApiKey
|
|
192
198
|
};
|
package/dist/messages/index.cjs
CHANGED
|
@@ -23,10 +23,37 @@ __export(messages_exports, {
|
|
|
23
23
|
SneekApiError: () => SneekApiError,
|
|
24
24
|
SneekClient: () => SneekClient,
|
|
25
25
|
SneekMessagesClient: () => SneekMessagesClient,
|
|
26
|
-
deriveKeys: () => deriveKeys
|
|
26
|
+
deriveKeys: () => deriveKeys,
|
|
27
|
+
isValidApiKey: () => isValidApiKey
|
|
27
28
|
});
|
|
28
29
|
module.exports = __toCommonJS(messages_exports);
|
|
29
30
|
|
|
31
|
+
// src/core/derive-keys.ts
|
|
32
|
+
var import_node_crypto = require("crypto");
|
|
33
|
+
var KEY_LABELS = {
|
|
34
|
+
qrSigningKey: "sneek-qr-v1",
|
|
35
|
+
webhookSigningKey: "sneek-webhook-v1",
|
|
36
|
+
proofKey: "sneek-proof-v1"
|
|
37
|
+
};
|
|
38
|
+
var API_KEY_PATTERN = /^sneek_[A-Za-z0-9_-]{43}$/;
|
|
39
|
+
function isValidApiKey(apiKey) {
|
|
40
|
+
return API_KEY_PATTERN.test(apiKey);
|
|
41
|
+
}
|
|
42
|
+
function deriveKeys(apiKey) {
|
|
43
|
+
if (typeof apiKey !== "string" || !isValidApiKey(apiKey)) {
|
|
44
|
+
throw new TypeError("apiKey must use the sneek_ format with a 43-character secret");
|
|
45
|
+
}
|
|
46
|
+
const inputKeyMaterial = Buffer.from(apiKey, "utf8");
|
|
47
|
+
const derive = (label) => Buffer.from(
|
|
48
|
+
(0, import_node_crypto.hkdfSync)("sha256", inputKeyMaterial, Buffer.alloc(0), label, 32)
|
|
49
|
+
);
|
|
50
|
+
return {
|
|
51
|
+
qrSigningKey: derive(KEY_LABELS.qrSigningKey),
|
|
52
|
+
webhookSigningKey: derive(KEY_LABELS.webhookSigningKey),
|
|
53
|
+
proofKey: derive(KEY_LABELS.proofKey)
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
|
|
30
57
|
// src/core/client.ts
|
|
31
58
|
var SneekApiError = class extends Error {
|
|
32
59
|
constructor(status, type, title, detail) {
|
|
@@ -51,6 +78,7 @@ var SneekClient = class {
|
|
|
51
78
|
constructor(options) {
|
|
52
79
|
if (!options.apiUrl) throw new Error("apiUrl is required");
|
|
53
80
|
if (!options.apiKey) throw new Error("apiKey is required");
|
|
81
|
+
if (!isValidApiKey(options.apiKey)) throw new Error("apiKey must use the sneek_ format with a 43-character secret");
|
|
54
82
|
this.apiUrl = options.apiUrl.replace(/\/+$/, "");
|
|
55
83
|
this.apiKey = options.apiKey;
|
|
56
84
|
this.fetchImpl = options.fetch ?? fetch;
|
|
@@ -122,28 +150,6 @@ function asProblem(value) {
|
|
|
122
150
|
};
|
|
123
151
|
}
|
|
124
152
|
|
|
125
|
-
// src/core/derive-keys.ts
|
|
126
|
-
var import_node_crypto = require("crypto");
|
|
127
|
-
var KEY_LABELS = {
|
|
128
|
-
qrSigningKey: "sneek-qr-v1",
|
|
129
|
-
webhookSigningKey: "sneek-webhook-v1",
|
|
130
|
-
proofKey: "sneek-proof-v1"
|
|
131
|
-
};
|
|
132
|
-
function deriveKeys(apiKey) {
|
|
133
|
-
if (typeof apiKey !== "string" || apiKey.length === 0) {
|
|
134
|
-
throw new TypeError("apiKey must be a nonempty string");
|
|
135
|
-
}
|
|
136
|
-
const inputKeyMaterial = Buffer.from(apiKey, "utf8");
|
|
137
|
-
const derive = (label) => Buffer.from(
|
|
138
|
-
(0, import_node_crypto.hkdfSync)("sha256", inputKeyMaterial, Buffer.alloc(0), label, 32)
|
|
139
|
-
);
|
|
140
|
-
return {
|
|
141
|
-
qrSigningKey: derive(KEY_LABELS.qrSigningKey),
|
|
142
|
-
webhookSigningKey: derive(KEY_LABELS.webhookSigningKey),
|
|
143
|
-
proofKey: derive(KEY_LABELS.proofKey)
|
|
144
|
-
};
|
|
145
|
-
}
|
|
146
|
-
|
|
147
153
|
// src/messages/client.ts
|
|
148
154
|
var SneekMessagesClient = class {
|
|
149
155
|
client;
|
|
@@ -166,5 +172,6 @@ var SneekMessagesClient = class {
|
|
|
166
172
|
SneekApiError,
|
|
167
173
|
SneekClient,
|
|
168
174
|
SneekMessagesClient,
|
|
169
|
-
deriveKeys
|
|
175
|
+
deriveKeys,
|
|
176
|
+
isValidApiKey
|
|
170
177
|
});
|
package/dist/messages/index.js
CHANGED
|
@@ -1,3 +1,29 @@
|
|
|
1
|
+
// src/core/derive-keys.ts
|
|
2
|
+
import { hkdfSync } from "crypto";
|
|
3
|
+
var KEY_LABELS = {
|
|
4
|
+
qrSigningKey: "sneek-qr-v1",
|
|
5
|
+
webhookSigningKey: "sneek-webhook-v1",
|
|
6
|
+
proofKey: "sneek-proof-v1"
|
|
7
|
+
};
|
|
8
|
+
var API_KEY_PATTERN = /^sneek_[A-Za-z0-9_-]{43}$/;
|
|
9
|
+
function isValidApiKey(apiKey) {
|
|
10
|
+
return API_KEY_PATTERN.test(apiKey);
|
|
11
|
+
}
|
|
12
|
+
function deriveKeys(apiKey) {
|
|
13
|
+
if (typeof apiKey !== "string" || !isValidApiKey(apiKey)) {
|
|
14
|
+
throw new TypeError("apiKey must use the sneek_ format with a 43-character secret");
|
|
15
|
+
}
|
|
16
|
+
const inputKeyMaterial = Buffer.from(apiKey, "utf8");
|
|
17
|
+
const derive = (label) => Buffer.from(
|
|
18
|
+
hkdfSync("sha256", inputKeyMaterial, Buffer.alloc(0), label, 32)
|
|
19
|
+
);
|
|
20
|
+
return {
|
|
21
|
+
qrSigningKey: derive(KEY_LABELS.qrSigningKey),
|
|
22
|
+
webhookSigningKey: derive(KEY_LABELS.webhookSigningKey),
|
|
23
|
+
proofKey: derive(KEY_LABELS.proofKey)
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
|
|
1
27
|
// src/core/client.ts
|
|
2
28
|
var SneekApiError = class extends Error {
|
|
3
29
|
constructor(status, type, title, detail) {
|
|
@@ -22,6 +48,7 @@ var SneekClient = class {
|
|
|
22
48
|
constructor(options) {
|
|
23
49
|
if (!options.apiUrl) throw new Error("apiUrl is required");
|
|
24
50
|
if (!options.apiKey) throw new Error("apiKey is required");
|
|
51
|
+
if (!isValidApiKey(options.apiKey)) throw new Error("apiKey must use the sneek_ format with a 43-character secret");
|
|
25
52
|
this.apiUrl = options.apiUrl.replace(/\/+$/, "");
|
|
26
53
|
this.apiKey = options.apiKey;
|
|
27
54
|
this.fetchImpl = options.fetch ?? fetch;
|
|
@@ -93,28 +120,6 @@ function asProblem(value) {
|
|
|
93
120
|
};
|
|
94
121
|
}
|
|
95
122
|
|
|
96
|
-
// src/core/derive-keys.ts
|
|
97
|
-
import { hkdfSync } from "crypto";
|
|
98
|
-
var KEY_LABELS = {
|
|
99
|
-
qrSigningKey: "sneek-qr-v1",
|
|
100
|
-
webhookSigningKey: "sneek-webhook-v1",
|
|
101
|
-
proofKey: "sneek-proof-v1"
|
|
102
|
-
};
|
|
103
|
-
function deriveKeys(apiKey) {
|
|
104
|
-
if (typeof apiKey !== "string" || apiKey.length === 0) {
|
|
105
|
-
throw new TypeError("apiKey must be a nonempty string");
|
|
106
|
-
}
|
|
107
|
-
const inputKeyMaterial = Buffer.from(apiKey, "utf8");
|
|
108
|
-
const derive = (label) => Buffer.from(
|
|
109
|
-
hkdfSync("sha256", inputKeyMaterial, Buffer.alloc(0), label, 32)
|
|
110
|
-
);
|
|
111
|
-
return {
|
|
112
|
-
qrSigningKey: derive(KEY_LABELS.qrSigningKey),
|
|
113
|
-
webhookSigningKey: derive(KEY_LABELS.webhookSigningKey),
|
|
114
|
-
proofKey: derive(KEY_LABELS.proofKey)
|
|
115
|
-
};
|
|
116
|
-
}
|
|
117
|
-
|
|
118
123
|
// src/messages/client.ts
|
|
119
124
|
var SneekMessagesClient = class {
|
|
120
125
|
client;
|
|
@@ -136,5 +141,6 @@ export {
|
|
|
136
141
|
SneekApiError,
|
|
137
142
|
SneekClient,
|
|
138
143
|
SneekMessagesClient,
|
|
139
|
-
deriveKeys
|
|
144
|
+
deriveKeys,
|
|
145
|
+
isValidApiKey
|
|
140
146
|
};
|
package/dist/pay/index.cjs
CHANGED
|
@@ -24,10 +24,37 @@ __export(pay_exports, {
|
|
|
24
24
|
SneekApiError: () => SneekApiError,
|
|
25
25
|
SneekClient: () => SneekClient,
|
|
26
26
|
SneekPayClient: () => SneekPayClient,
|
|
27
|
-
deriveKeys: () => deriveKeys
|
|
27
|
+
deriveKeys: () => deriveKeys,
|
|
28
|
+
isValidApiKey: () => isValidApiKey
|
|
28
29
|
});
|
|
29
30
|
module.exports = __toCommonJS(pay_exports);
|
|
30
31
|
|
|
32
|
+
// src/core/derive-keys.ts
|
|
33
|
+
var import_node_crypto = require("crypto");
|
|
34
|
+
var KEY_LABELS = {
|
|
35
|
+
qrSigningKey: "sneek-qr-v1",
|
|
36
|
+
webhookSigningKey: "sneek-webhook-v1",
|
|
37
|
+
proofKey: "sneek-proof-v1"
|
|
38
|
+
};
|
|
39
|
+
var API_KEY_PATTERN = /^sneek_[A-Za-z0-9_-]{43}$/;
|
|
40
|
+
function isValidApiKey(apiKey) {
|
|
41
|
+
return API_KEY_PATTERN.test(apiKey);
|
|
42
|
+
}
|
|
43
|
+
function deriveKeys(apiKey) {
|
|
44
|
+
if (typeof apiKey !== "string" || !isValidApiKey(apiKey)) {
|
|
45
|
+
throw new TypeError("apiKey must use the sneek_ format with a 43-character secret");
|
|
46
|
+
}
|
|
47
|
+
const inputKeyMaterial = Buffer.from(apiKey, "utf8");
|
|
48
|
+
const derive = (label) => Buffer.from(
|
|
49
|
+
(0, import_node_crypto.hkdfSync)("sha256", inputKeyMaterial, Buffer.alloc(0), label, 32)
|
|
50
|
+
);
|
|
51
|
+
return {
|
|
52
|
+
qrSigningKey: derive(KEY_LABELS.qrSigningKey),
|
|
53
|
+
webhookSigningKey: derive(KEY_LABELS.webhookSigningKey),
|
|
54
|
+
proofKey: derive(KEY_LABELS.proofKey)
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
|
|
31
58
|
// src/core/client.ts
|
|
32
59
|
var SneekApiError = class extends Error {
|
|
33
60
|
constructor(status, type, title, detail) {
|
|
@@ -52,6 +79,7 @@ var SneekClient = class {
|
|
|
52
79
|
constructor(options) {
|
|
53
80
|
if (!options.apiUrl) throw new Error("apiUrl is required");
|
|
54
81
|
if (!options.apiKey) throw new Error("apiKey is required");
|
|
82
|
+
if (!isValidApiKey(options.apiKey)) throw new Error("apiKey must use the sneek_ format with a 43-character secret");
|
|
55
83
|
this.apiUrl = options.apiUrl.replace(/\/+$/, "");
|
|
56
84
|
this.apiKey = options.apiKey;
|
|
57
85
|
this.fetchImpl = options.fetch ?? fetch;
|
|
@@ -123,28 +151,6 @@ function asProblem(value) {
|
|
|
123
151
|
};
|
|
124
152
|
}
|
|
125
153
|
|
|
126
|
-
// src/core/derive-keys.ts
|
|
127
|
-
var import_node_crypto = require("crypto");
|
|
128
|
-
var KEY_LABELS = {
|
|
129
|
-
qrSigningKey: "sneek-qr-v1",
|
|
130
|
-
webhookSigningKey: "sneek-webhook-v1",
|
|
131
|
-
proofKey: "sneek-proof-v1"
|
|
132
|
-
};
|
|
133
|
-
function deriveKeys(apiKey) {
|
|
134
|
-
if (typeof apiKey !== "string" || apiKey.length === 0) {
|
|
135
|
-
throw new TypeError("apiKey must be a nonempty string");
|
|
136
|
-
}
|
|
137
|
-
const inputKeyMaterial = Buffer.from(apiKey, "utf8");
|
|
138
|
-
const derive = (label) => Buffer.from(
|
|
139
|
-
(0, import_node_crypto.hkdfSync)("sha256", inputKeyMaterial, Buffer.alloc(0), label, 32)
|
|
140
|
-
);
|
|
141
|
-
return {
|
|
142
|
-
qrSigningKey: derive(KEY_LABELS.qrSigningKey),
|
|
143
|
-
webhookSigningKey: derive(KEY_LABELS.webhookSigningKey),
|
|
144
|
-
proofKey: derive(KEY_LABELS.proofKey)
|
|
145
|
-
};
|
|
146
|
-
}
|
|
147
|
-
|
|
148
154
|
// src/pay/payments.ts
|
|
149
155
|
var SneekPayClient = class {
|
|
150
156
|
client;
|
|
@@ -219,5 +225,6 @@ var OrdersClient = class {
|
|
|
219
225
|
SneekApiError,
|
|
220
226
|
SneekClient,
|
|
221
227
|
SneekPayClient,
|
|
222
|
-
deriveKeys
|
|
228
|
+
deriveKeys,
|
|
229
|
+
isValidApiKey
|
|
223
230
|
});
|
package/dist/pay/index.js
CHANGED
|
@@ -1,3 +1,29 @@
|
|
|
1
|
+
// src/core/derive-keys.ts
|
|
2
|
+
import { hkdfSync } from "crypto";
|
|
3
|
+
var KEY_LABELS = {
|
|
4
|
+
qrSigningKey: "sneek-qr-v1",
|
|
5
|
+
webhookSigningKey: "sneek-webhook-v1",
|
|
6
|
+
proofKey: "sneek-proof-v1"
|
|
7
|
+
};
|
|
8
|
+
var API_KEY_PATTERN = /^sneek_[A-Za-z0-9_-]{43}$/;
|
|
9
|
+
function isValidApiKey(apiKey) {
|
|
10
|
+
return API_KEY_PATTERN.test(apiKey);
|
|
11
|
+
}
|
|
12
|
+
function deriveKeys(apiKey) {
|
|
13
|
+
if (typeof apiKey !== "string" || !isValidApiKey(apiKey)) {
|
|
14
|
+
throw new TypeError("apiKey must use the sneek_ format with a 43-character secret");
|
|
15
|
+
}
|
|
16
|
+
const inputKeyMaterial = Buffer.from(apiKey, "utf8");
|
|
17
|
+
const derive = (label) => Buffer.from(
|
|
18
|
+
hkdfSync("sha256", inputKeyMaterial, Buffer.alloc(0), label, 32)
|
|
19
|
+
);
|
|
20
|
+
return {
|
|
21
|
+
qrSigningKey: derive(KEY_LABELS.qrSigningKey),
|
|
22
|
+
webhookSigningKey: derive(KEY_LABELS.webhookSigningKey),
|
|
23
|
+
proofKey: derive(KEY_LABELS.proofKey)
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
|
|
1
27
|
// src/core/client.ts
|
|
2
28
|
var SneekApiError = class extends Error {
|
|
3
29
|
constructor(status, type, title, detail) {
|
|
@@ -22,6 +48,7 @@ var SneekClient = class {
|
|
|
22
48
|
constructor(options) {
|
|
23
49
|
if (!options.apiUrl) throw new Error("apiUrl is required");
|
|
24
50
|
if (!options.apiKey) throw new Error("apiKey is required");
|
|
51
|
+
if (!isValidApiKey(options.apiKey)) throw new Error("apiKey must use the sneek_ format with a 43-character secret");
|
|
25
52
|
this.apiUrl = options.apiUrl.replace(/\/+$/, "");
|
|
26
53
|
this.apiKey = options.apiKey;
|
|
27
54
|
this.fetchImpl = options.fetch ?? fetch;
|
|
@@ -93,28 +120,6 @@ function asProblem(value) {
|
|
|
93
120
|
};
|
|
94
121
|
}
|
|
95
122
|
|
|
96
|
-
// src/core/derive-keys.ts
|
|
97
|
-
import { hkdfSync } from "crypto";
|
|
98
|
-
var KEY_LABELS = {
|
|
99
|
-
qrSigningKey: "sneek-qr-v1",
|
|
100
|
-
webhookSigningKey: "sneek-webhook-v1",
|
|
101
|
-
proofKey: "sneek-proof-v1"
|
|
102
|
-
};
|
|
103
|
-
function deriveKeys(apiKey) {
|
|
104
|
-
if (typeof apiKey !== "string" || apiKey.length === 0) {
|
|
105
|
-
throw new TypeError("apiKey must be a nonempty string");
|
|
106
|
-
}
|
|
107
|
-
const inputKeyMaterial = Buffer.from(apiKey, "utf8");
|
|
108
|
-
const derive = (label) => Buffer.from(
|
|
109
|
-
hkdfSync("sha256", inputKeyMaterial, Buffer.alloc(0), label, 32)
|
|
110
|
-
);
|
|
111
|
-
return {
|
|
112
|
-
qrSigningKey: derive(KEY_LABELS.qrSigningKey),
|
|
113
|
-
webhookSigningKey: derive(KEY_LABELS.webhookSigningKey),
|
|
114
|
-
proofKey: derive(KEY_LABELS.proofKey)
|
|
115
|
-
};
|
|
116
|
-
}
|
|
117
|
-
|
|
118
123
|
// src/pay/payments.ts
|
|
119
124
|
var SneekPayClient = class {
|
|
120
125
|
client;
|
|
@@ -188,5 +193,6 @@ export {
|
|
|
188
193
|
SneekApiError,
|
|
189
194
|
SneekClient,
|
|
190
195
|
SneekPayClient,
|
|
191
|
-
deriveKeys
|
|
196
|
+
deriveKeys,
|
|
197
|
+
isValidApiKey
|
|
192
198
|
};
|
|
@@ -38,12 +38,12 @@ export declare const SneekVerifyActionSchema: z.ZodUnion<[z.ZodObject<{
|
|
|
38
38
|
}, "strict", z.ZodTypeAny, {
|
|
39
39
|
action: "switch";
|
|
40
40
|
requestId: string;
|
|
41
|
-
channel: "
|
|
41
|
+
channel: "sms" | "whatsapp" | "email" | "push";
|
|
42
42
|
proof: string;
|
|
43
43
|
}, {
|
|
44
44
|
action: "switch";
|
|
45
45
|
requestId: string;
|
|
46
|
-
channel: "
|
|
46
|
+
channel: "sms" | "whatsapp" | "email" | "push";
|
|
47
47
|
proof: string;
|
|
48
48
|
}>, z.ZodObject<{
|
|
49
49
|
action: z.ZodLiteral<"verify">;
|
package/dist/verify/index.cjs
CHANGED
|
@@ -23,10 +23,37 @@ __export(verify_exports, {
|
|
|
23
23
|
SneekApiError: () => SneekApiError,
|
|
24
24
|
SneekClient: () => SneekClient,
|
|
25
25
|
SneekVerifyHandler: () => SneekVerifyHandler,
|
|
26
|
-
deriveKeys: () => deriveKeys
|
|
26
|
+
deriveKeys: () => deriveKeys,
|
|
27
|
+
isValidApiKey: () => isValidApiKey
|
|
27
28
|
});
|
|
28
29
|
module.exports = __toCommonJS(verify_exports);
|
|
29
30
|
|
|
31
|
+
// src/core/derive-keys.ts
|
|
32
|
+
var import_node_crypto = require("crypto");
|
|
33
|
+
var KEY_LABELS = {
|
|
34
|
+
qrSigningKey: "sneek-qr-v1",
|
|
35
|
+
webhookSigningKey: "sneek-webhook-v1",
|
|
36
|
+
proofKey: "sneek-proof-v1"
|
|
37
|
+
};
|
|
38
|
+
var API_KEY_PATTERN = /^sneek_[A-Za-z0-9_-]{43}$/;
|
|
39
|
+
function isValidApiKey(apiKey) {
|
|
40
|
+
return API_KEY_PATTERN.test(apiKey);
|
|
41
|
+
}
|
|
42
|
+
function deriveKeys(apiKey) {
|
|
43
|
+
if (typeof apiKey !== "string" || !isValidApiKey(apiKey)) {
|
|
44
|
+
throw new TypeError("apiKey must use the sneek_ format with a 43-character secret");
|
|
45
|
+
}
|
|
46
|
+
const inputKeyMaterial = Buffer.from(apiKey, "utf8");
|
|
47
|
+
const derive = (label) => Buffer.from(
|
|
48
|
+
(0, import_node_crypto.hkdfSync)("sha256", inputKeyMaterial, Buffer.alloc(0), label, 32)
|
|
49
|
+
);
|
|
50
|
+
return {
|
|
51
|
+
qrSigningKey: derive(KEY_LABELS.qrSigningKey),
|
|
52
|
+
webhookSigningKey: derive(KEY_LABELS.webhookSigningKey),
|
|
53
|
+
proofKey: derive(KEY_LABELS.proofKey)
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
|
|
30
57
|
// src/core/client.ts
|
|
31
58
|
var SneekApiError = class extends Error {
|
|
32
59
|
constructor(status, type, title, detail) {
|
|
@@ -51,6 +78,7 @@ var SneekClient = class {
|
|
|
51
78
|
constructor(options) {
|
|
52
79
|
if (!options.apiUrl) throw new Error("apiUrl is required");
|
|
53
80
|
if (!options.apiKey) throw new Error("apiKey is required");
|
|
81
|
+
if (!isValidApiKey(options.apiKey)) throw new Error("apiKey must use the sneek_ format with a 43-character secret");
|
|
54
82
|
this.apiUrl = options.apiUrl.replace(/\/+$/, "");
|
|
55
83
|
this.apiKey = options.apiKey;
|
|
56
84
|
this.fetchImpl = options.fetch ?? fetch;
|
|
@@ -122,28 +150,6 @@ function asProblem(value) {
|
|
|
122
150
|
};
|
|
123
151
|
}
|
|
124
152
|
|
|
125
|
-
// src/core/derive-keys.ts
|
|
126
|
-
var import_node_crypto = require("crypto");
|
|
127
|
-
var KEY_LABELS = {
|
|
128
|
-
qrSigningKey: "sneek-qr-v1",
|
|
129
|
-
webhookSigningKey: "sneek-webhook-v1",
|
|
130
|
-
proofKey: "sneek-proof-v1"
|
|
131
|
-
};
|
|
132
|
-
function deriveKeys(apiKey) {
|
|
133
|
-
if (typeof apiKey !== "string" || apiKey.length === 0) {
|
|
134
|
-
throw new TypeError("apiKey must be a nonempty string");
|
|
135
|
-
}
|
|
136
|
-
const inputKeyMaterial = Buffer.from(apiKey, "utf8");
|
|
137
|
-
const derive = (label) => Buffer.from(
|
|
138
|
-
(0, import_node_crypto.hkdfSync)("sha256", inputKeyMaterial, Buffer.alloc(0), label, 32)
|
|
139
|
-
);
|
|
140
|
-
return {
|
|
141
|
-
qrSigningKey: derive(KEY_LABELS.qrSigningKey),
|
|
142
|
-
webhookSigningKey: derive(KEY_LABELS.webhookSigningKey),
|
|
143
|
-
proofKey: derive(KEY_LABELS.proofKey)
|
|
144
|
-
};
|
|
145
|
-
}
|
|
146
|
-
|
|
147
153
|
// src/verify/handler.ts
|
|
148
154
|
var import_node_crypto2 = require("crypto");
|
|
149
155
|
var import_jose = require("jose");
|
|
@@ -419,11 +425,11 @@ var SneekVerifyHandler = class {
|
|
|
419
425
|
const partner = await this.partnerConfig();
|
|
420
426
|
if (!partner.origins.includes(origin)) return jsonResponse({ error: "Origin is not registered for QR verification" }, 403);
|
|
421
427
|
const nonce = (0, import_node_crypto2.randomBytes)(32).toString("hex");
|
|
422
|
-
const ref = (0, import_node_crypto2.createHash)("sha256").update(nonce).digest("hex");
|
|
428
|
+
const ref = (0, import_node_crypto2.createHash)("sha256").update(Buffer.from(nonce, "hex")).digest("hex");
|
|
423
429
|
const issuedAt = Math.floor(Date.now() / 1e3);
|
|
424
430
|
const expiresAt = (issuedAt + partner.qrTtlSeconds) * 1e3;
|
|
425
431
|
const bindingProof = (0, import_node_crypto2.randomBytes)(32).toString("base64url");
|
|
426
|
-
const signature = (0, import_node_crypto2.createHmac)("sha256", this.keys.qrSigningKey).update(["sneek-qr-v1", partner.applicationId, nonce, origin, String(issuedAt)].join("\n")).digest().subarray(0, 16).toString("base64url");
|
|
432
|
+
const signature = (0, import_node_crypto2.createHmac)("sha256", this.keys.qrSigningKey).update(["sneek-qr-v1", partner.applicationId, partner.kid, nonce, origin, String(issuedAt)].join("\n")).digest().subarray(0, 16).toString("base64url");
|
|
427
433
|
await this.approvalStore.createQrSession({
|
|
428
434
|
ref,
|
|
429
435
|
applicationId: partner.applicationId,
|
|
@@ -431,7 +437,7 @@ var SneekVerifyHandler = class {
|
|
|
431
437
|
bindingProofHash: this.hash(bindingProof),
|
|
432
438
|
expiresAt
|
|
433
439
|
});
|
|
434
|
-
return jsonResponse({ ref, nonce, issuedAt, expiresAt, signature, bindingProof }, 200);
|
|
440
|
+
return jsonResponse({ ref, nonce, issuedAt, expiresAt, kid: partner.kid, signature, bindingProof }, 200);
|
|
435
441
|
}
|
|
436
442
|
async qrStatus(ref, bindingProof, origin) {
|
|
437
443
|
const session = await this.qrSession(ref, bindingProof, origin);
|
|
@@ -467,5 +473,6 @@ function jsonResponse(body, status) {
|
|
|
467
473
|
SneekApiError,
|
|
468
474
|
SneekClient,
|
|
469
475
|
SneekVerifyHandler,
|
|
470
|
-
deriveKeys
|
|
476
|
+
deriveKeys,
|
|
477
|
+
isValidApiKey
|
|
471
478
|
});
|
package/dist/verify/index.js
CHANGED
|
@@ -1,3 +1,29 @@
|
|
|
1
|
+
// src/core/derive-keys.ts
|
|
2
|
+
import { hkdfSync } from "crypto";
|
|
3
|
+
var KEY_LABELS = {
|
|
4
|
+
qrSigningKey: "sneek-qr-v1",
|
|
5
|
+
webhookSigningKey: "sneek-webhook-v1",
|
|
6
|
+
proofKey: "sneek-proof-v1"
|
|
7
|
+
};
|
|
8
|
+
var API_KEY_PATTERN = /^sneek_[A-Za-z0-9_-]{43}$/;
|
|
9
|
+
function isValidApiKey(apiKey) {
|
|
10
|
+
return API_KEY_PATTERN.test(apiKey);
|
|
11
|
+
}
|
|
12
|
+
function deriveKeys(apiKey) {
|
|
13
|
+
if (typeof apiKey !== "string" || !isValidApiKey(apiKey)) {
|
|
14
|
+
throw new TypeError("apiKey must use the sneek_ format with a 43-character secret");
|
|
15
|
+
}
|
|
16
|
+
const inputKeyMaterial = Buffer.from(apiKey, "utf8");
|
|
17
|
+
const derive = (label) => Buffer.from(
|
|
18
|
+
hkdfSync("sha256", inputKeyMaterial, Buffer.alloc(0), label, 32)
|
|
19
|
+
);
|
|
20
|
+
return {
|
|
21
|
+
qrSigningKey: derive(KEY_LABELS.qrSigningKey),
|
|
22
|
+
webhookSigningKey: derive(KEY_LABELS.webhookSigningKey),
|
|
23
|
+
proofKey: derive(KEY_LABELS.proofKey)
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
|
|
1
27
|
// src/core/client.ts
|
|
2
28
|
var SneekApiError = class extends Error {
|
|
3
29
|
constructor(status, type, title, detail) {
|
|
@@ -22,6 +48,7 @@ var SneekClient = class {
|
|
|
22
48
|
constructor(options) {
|
|
23
49
|
if (!options.apiUrl) throw new Error("apiUrl is required");
|
|
24
50
|
if (!options.apiKey) throw new Error("apiKey is required");
|
|
51
|
+
if (!isValidApiKey(options.apiKey)) throw new Error("apiKey must use the sneek_ format with a 43-character secret");
|
|
25
52
|
this.apiUrl = options.apiUrl.replace(/\/+$/, "");
|
|
26
53
|
this.apiKey = options.apiKey;
|
|
27
54
|
this.fetchImpl = options.fetch ?? fetch;
|
|
@@ -93,28 +120,6 @@ function asProblem(value) {
|
|
|
93
120
|
};
|
|
94
121
|
}
|
|
95
122
|
|
|
96
|
-
// src/core/derive-keys.ts
|
|
97
|
-
import { hkdfSync } from "crypto";
|
|
98
|
-
var KEY_LABELS = {
|
|
99
|
-
qrSigningKey: "sneek-qr-v1",
|
|
100
|
-
webhookSigningKey: "sneek-webhook-v1",
|
|
101
|
-
proofKey: "sneek-proof-v1"
|
|
102
|
-
};
|
|
103
|
-
function deriveKeys(apiKey) {
|
|
104
|
-
if (typeof apiKey !== "string" || apiKey.length === 0) {
|
|
105
|
-
throw new TypeError("apiKey must be a nonempty string");
|
|
106
|
-
}
|
|
107
|
-
const inputKeyMaterial = Buffer.from(apiKey, "utf8");
|
|
108
|
-
const derive = (label) => Buffer.from(
|
|
109
|
-
hkdfSync("sha256", inputKeyMaterial, Buffer.alloc(0), label, 32)
|
|
110
|
-
);
|
|
111
|
-
return {
|
|
112
|
-
qrSigningKey: derive(KEY_LABELS.qrSigningKey),
|
|
113
|
-
webhookSigningKey: derive(KEY_LABELS.webhookSigningKey),
|
|
114
|
-
proofKey: derive(KEY_LABELS.proofKey)
|
|
115
|
-
};
|
|
116
|
-
}
|
|
117
|
-
|
|
118
123
|
// src/verify/handler.ts
|
|
119
124
|
import { createHash, createHmac, randomBytes, timingSafeEqual } from "crypto";
|
|
120
125
|
import { createRemoteJWKSet, jwtVerify } from "jose";
|
|
@@ -390,11 +395,11 @@ var SneekVerifyHandler = class {
|
|
|
390
395
|
const partner = await this.partnerConfig();
|
|
391
396
|
if (!partner.origins.includes(origin)) return jsonResponse({ error: "Origin is not registered for QR verification" }, 403);
|
|
392
397
|
const nonce = randomBytes(32).toString("hex");
|
|
393
|
-
const ref = createHash("sha256").update(nonce).digest("hex");
|
|
398
|
+
const ref = createHash("sha256").update(Buffer.from(nonce, "hex")).digest("hex");
|
|
394
399
|
const issuedAt = Math.floor(Date.now() / 1e3);
|
|
395
400
|
const expiresAt = (issuedAt + partner.qrTtlSeconds) * 1e3;
|
|
396
401
|
const bindingProof = randomBytes(32).toString("base64url");
|
|
397
|
-
const signature = createHmac("sha256", this.keys.qrSigningKey).update(["sneek-qr-v1", partner.applicationId, nonce, origin, String(issuedAt)].join("\n")).digest().subarray(0, 16).toString("base64url");
|
|
402
|
+
const signature = createHmac("sha256", this.keys.qrSigningKey).update(["sneek-qr-v1", partner.applicationId, partner.kid, nonce, origin, String(issuedAt)].join("\n")).digest().subarray(0, 16).toString("base64url");
|
|
398
403
|
await this.approvalStore.createQrSession({
|
|
399
404
|
ref,
|
|
400
405
|
applicationId: partner.applicationId,
|
|
@@ -402,7 +407,7 @@ var SneekVerifyHandler = class {
|
|
|
402
407
|
bindingProofHash: this.hash(bindingProof),
|
|
403
408
|
expiresAt
|
|
404
409
|
});
|
|
405
|
-
return jsonResponse({ ref, nonce, issuedAt, expiresAt, signature, bindingProof }, 200);
|
|
410
|
+
return jsonResponse({ ref, nonce, issuedAt, expiresAt, kid: partner.kid, signature, bindingProof }, 200);
|
|
406
411
|
}
|
|
407
412
|
async qrStatus(ref, bindingProof, origin) {
|
|
408
413
|
const session = await this.qrSession(ref, bindingProof, origin);
|
|
@@ -437,5 +442,6 @@ export {
|
|
|
437
442
|
SneekApiError,
|
|
438
443
|
SneekClient,
|
|
439
444
|
SneekVerifyHandler,
|
|
440
|
-
deriveKeys
|
|
445
|
+
deriveKeys,
|
|
446
|
+
isValidApiKey
|
|
441
447
|
};
|