@sneekin/sdk 1.1.0 → 1.1.2
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 +283 -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 +44 -29
- package/dist/verify/index.js +43 -29
- package/package.json +2 -2
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");
|
|
@@ -334,8 +340,16 @@ var SneekVerifyHandler = class {
|
|
|
334
340
|
const partner = await this.client.request("GET", "/api/verify/qr/partner-config");
|
|
335
341
|
let payload;
|
|
336
342
|
try {
|
|
337
|
-
|
|
338
|
-
|
|
343
|
+
let jwks = this.jwksByIssuer.get(partner.issuer);
|
|
344
|
+
if (!jwks) {
|
|
345
|
+
try {
|
|
346
|
+
const localJwksData = await this.client.request("GET", "/oauth/jwks");
|
|
347
|
+
jwks = (0, import_jose.createLocalJWKSet)(localJwksData);
|
|
348
|
+
} catch {
|
|
349
|
+
jwks = (0, import_jose.createRemoteJWKSet)(new URL("/oauth/jwks", partner.issuer));
|
|
350
|
+
}
|
|
351
|
+
this.jwksByIssuer.set(partner.issuer, jwks);
|
|
352
|
+
}
|
|
339
353
|
({ payload } = await (0, import_jose.jwtVerify)(result.idToken, jwks, {
|
|
340
354
|
issuer: partner.issuer,
|
|
341
355
|
audience: partner.clientId
|
|
@@ -419,11 +433,11 @@ var SneekVerifyHandler = class {
|
|
|
419
433
|
const partner = await this.partnerConfig();
|
|
420
434
|
if (!partner.origins.includes(origin)) return jsonResponse({ error: "Origin is not registered for QR verification" }, 403);
|
|
421
435
|
const nonce = (0, import_node_crypto2.randomBytes)(32).toString("hex");
|
|
422
|
-
const ref = (0, import_node_crypto2.createHash)("sha256").update(nonce).digest("hex");
|
|
436
|
+
const ref = (0, import_node_crypto2.createHash)("sha256").update(Buffer.from(nonce, "hex")).digest("hex");
|
|
423
437
|
const issuedAt = Math.floor(Date.now() / 1e3);
|
|
424
438
|
const expiresAt = (issuedAt + partner.qrTtlSeconds) * 1e3;
|
|
425
439
|
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");
|
|
440
|
+
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
441
|
await this.approvalStore.createQrSession({
|
|
428
442
|
ref,
|
|
429
443
|
applicationId: partner.applicationId,
|
|
@@ -431,7 +445,7 @@ var SneekVerifyHandler = class {
|
|
|
431
445
|
bindingProofHash: this.hash(bindingProof),
|
|
432
446
|
expiresAt
|
|
433
447
|
});
|
|
434
|
-
return jsonResponse({ ref, nonce, issuedAt, expiresAt, signature, bindingProof }, 200);
|
|
448
|
+
return jsonResponse({ ref, nonce, issuedAt, expiresAt, kid: partner.kid, signature, bindingProof }, 200);
|
|
435
449
|
}
|
|
436
450
|
async qrStatus(ref, bindingProof, origin) {
|
|
437
451
|
const session = await this.qrSession(ref, bindingProof, origin);
|
|
@@ -467,5 +481,6 @@ function jsonResponse(body, status) {
|
|
|
467
481
|
SneekApiError,
|
|
468
482
|
SneekClient,
|
|
469
483
|
SneekVerifyHandler,
|
|
470
|
-
deriveKeys
|
|
484
|
+
deriveKeys,
|
|
485
|
+
isValidApiKey
|
|
471
486
|
});
|