@mpgd/game-services 0.8.2 → 0.10.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.
- package/dist/admob-ssv-conformance.d.ts +19 -0
- package/dist/admob-ssv-conformance.js +258 -0
- package/dist/admob-ssv.d.ts +54 -0
- package/dist/admob-ssv.js +566 -0
- package/dist/app-store-verifier-conformance.d.ts +25 -0
- package/dist/app-store-verifier-conformance.js +28 -0
- package/dist/app-store-verifier.d.ts +87 -0
- package/dist/app-store-verifier.js +439 -0
- package/dist/apps-in-toss-evidence-verification-conformance.d.ts +26 -0
- package/dist/apps-in-toss-evidence-verification-conformance.js +613 -0
- package/dist/apps-in-toss-evidence-verification.d.ts +162 -0
- package/dist/apps-in-toss-evidence-verification.js +458 -0
- package/dist/client.js +51 -5
- package/dist/evidence-verification.d.ts +21 -1
- package/dist/google-play-purchase-conformance.d.ts +26 -0
- package/dist/google-play-purchase-conformance.js +39 -0
- package/dist/google-play-purchase.d.ts +40 -0
- package/dist/google-play-purchase.js +559 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.js +4 -0
- package/dist/notification-delivery.js +1 -0
- package/dist/runtime.js +2 -1
- package/dist/server.d.ts +3 -1
- package/dist/server.js +199 -14
- package/dist/types.d.ts +15 -3
- package/dist/types.js +47 -2
- package/dist/verified-leaderboard-durability-conformance.d.ts +39 -0
- package/dist/verified-leaderboard-durability-conformance.js +193 -0
- package/package.json +42 -5
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { AdPlacements } from '@mpgd/catalog';
|
|
2
|
+
import type { GameServicesEvidenceVerifier } from './evidence-verification';
|
|
3
|
+
import type { ClaimAdRewardRequest } from './types';
|
|
4
|
+
export declare const adMobSsvConformanceChecks: readonly ['verified callback emits one transaction authority identity', 'missing callback remains pending', 'tampered signature fails closed', 'AdMob-decoded signed query bytes accept equivalent percent-encoding', 'missing and duplicate signed fields fail closed', 'unknown key fails closed', 'secp256k1 key feed entries verify', 'signed identity mismatch fails closed', 'timestamp age and future-skew boundaries fail closed', 'callbacks sharing one signed transaction preserve one authority identity'];
|
|
5
|
+
export interface AdMobSsvConformanceReport {
|
|
6
|
+
readonly checks: readonly string[];
|
|
7
|
+
readonly passed: true;
|
|
8
|
+
}
|
|
9
|
+
export interface RunAdMobSsvConformanceInput {
|
|
10
|
+
readonly subtle?: SubtleCrypto;
|
|
11
|
+
}
|
|
12
|
+
export interface AdMobSsvConformanceFixture {
|
|
13
|
+
readonly verifier: GameServicesEvidenceVerifier;
|
|
14
|
+
readonly placements: AdPlacements;
|
|
15
|
+
readonly firstRequest: ClaimAdRewardRequest;
|
|
16
|
+
readonly replayRequest: ClaimAdRewardRequest;
|
|
17
|
+
}
|
|
18
|
+
export declare function createAdMobSsvConformanceFixture(input?: RunAdMobSsvConformanceInput): Promise<AdMobSsvConformanceFixture>;
|
|
19
|
+
export declare function runAdMobSsvConformance(input?: RunAdMobSsvConformanceInput): Promise<AdMobSsvConformanceReport>;
|
|
@@ -0,0 +1,258 @@
|
|
|
1
|
+
import { createAdMobSsvEvidenceVerifier, importAdMobSsvPublicKey, } from './admob-ssv.js';
|
|
2
|
+
export const adMobSsvConformanceChecks = [
|
|
3
|
+
'verified callback emits one transaction authority identity',
|
|
4
|
+
'missing callback remains pending',
|
|
5
|
+
'tampered signature fails closed',
|
|
6
|
+
'AdMob-decoded signed query bytes accept equivalent percent-encoding',
|
|
7
|
+
'missing and duplicate signed fields fail closed',
|
|
8
|
+
'unknown key fails closed',
|
|
9
|
+
'secp256k1 key feed entries verify',
|
|
10
|
+
'signed identity mismatch fails closed',
|
|
11
|
+
'timestamp age and future-skew boundaries fail closed',
|
|
12
|
+
'callbacks sharing one signed transaction preserve one authority identity',
|
|
13
|
+
];
|
|
14
|
+
const fixtureTimestampMs = 1784160000000;
|
|
15
|
+
const fixtureKeyId = '1234567890';
|
|
16
|
+
const fixturePublicKey = 'MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEvYnh4p45wAsdENipvmqwXzvdNaCgRqx2IvxoYI8kiummEYytzHIhL738YLr3vs5vG/A8xY8QiCLDqVV2c5sUZw==';
|
|
17
|
+
const firstFixtureSignature = 'MEYCIQDR1_VmQ4xw4WHff8KGDgv4insP7p5VAw8MhP5mZTFTgAIhAJ2Ejy5MU75UxeAxFqdLzvJwzL43qXl3PwuHMGYbjaiR';
|
|
18
|
+
const secondFixtureSignature = 'MEYCIQCq2WuuqIuZmykTaoF0fCZYgLmaYS8fdqNosnuK7UTDyQIhAJRNgIDOqFFvMGboT37xjjynNi8sYlI5_l4y-qUmQeR4';
|
|
19
|
+
const secp256k1FixtureKeyId = '3901585526';
|
|
20
|
+
const secp256k1FixturePublicKey = 'MFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEYWHOBDbohSMvoXvGOhnElOsG6JzFP3K3dbpoJqOF7xzRwM0FGLLSwIvECbFxctV5pcq7JVAut5Imaa75p+lcKw==';
|
|
21
|
+
const secp256k1FixtureSignature = 'MEYCIQDXWRwz4J2pZbcRcQJyNFI3cwQDeC5aulegoedKeJ9EcwIhAJnkRWFOzL4KD2hyWRdmSp3lYGPcrN_yPYyM2nfDt4Of';
|
|
22
|
+
const fixtureTransactionId = '18fa792de1bca816048293fc71035638';
|
|
23
|
+
const secp256k1FixtureTransactionId = '28fa792de1bca816048293fc71035639';
|
|
24
|
+
const placement = {
|
|
25
|
+
id: 'CONTINUE_AFTER_FAIL',
|
|
26
|
+
type: 'rewarded',
|
|
27
|
+
reward: {
|
|
28
|
+
type: 'continue',
|
|
29
|
+
amount: 1,
|
|
30
|
+
},
|
|
31
|
+
frequencyCap: {
|
|
32
|
+
cooldownSeconds: 60,
|
|
33
|
+
maxPerSession: 3,
|
|
34
|
+
},
|
|
35
|
+
platformPlacementIds: {
|
|
36
|
+
android: 'ca-app-pub-test/reward_continue',
|
|
37
|
+
ios: 'ca-app-pub-test/reward_continue',
|
|
38
|
+
},
|
|
39
|
+
};
|
|
40
|
+
const placements = {
|
|
41
|
+
version: 'admob-ssv-conformance',
|
|
42
|
+
placements: [placement],
|
|
43
|
+
};
|
|
44
|
+
async function createAdMobSsvConformanceContext(input, options) {
|
|
45
|
+
const subtle = input.subtle ?? readGlobalSubtleCrypto();
|
|
46
|
+
const publicKey = await importAdMobSsvPublicKey(fixturePublicKey, subtle);
|
|
47
|
+
const callbacks = new Map([
|
|
48
|
+
['reward-1', fixtureCallback('reward-1', firstFixtureSignature)],
|
|
49
|
+
['reward-2', fixtureCallback('reward-2', secondFixtureSignature)],
|
|
50
|
+
]);
|
|
51
|
+
const publicKeys = new Map([[fixtureKeyId, publicKey]]);
|
|
52
|
+
if (options.includeSecp256k1Fixture) {
|
|
53
|
+
const secp256k1PublicKey = await importAdMobSsvPublicKey(secp256k1FixturePublicKey, subtle);
|
|
54
|
+
callbacks.set('reward-secp', fixtureCallback('reward-secp', secp256k1FixtureSignature, {
|
|
55
|
+
keyId: secp256k1FixtureKeyId,
|
|
56
|
+
transactionId: secp256k1FixtureTransactionId,
|
|
57
|
+
}));
|
|
58
|
+
publicKeys.set(secp256k1FixtureKeyId, secp256k1PublicKey);
|
|
59
|
+
}
|
|
60
|
+
const callbackSource = mapCallbackSource(callbacks);
|
|
61
|
+
const publicKeySource = fixedPublicKeySource(publicKeys);
|
|
62
|
+
return {
|
|
63
|
+
callbackSource,
|
|
64
|
+
publicKeySource,
|
|
65
|
+
subtle,
|
|
66
|
+
verifier: createAdMobSsvEvidenceVerifier({
|
|
67
|
+
callbackSource,
|
|
68
|
+
publicKeySource,
|
|
69
|
+
subtle,
|
|
70
|
+
now: () => fixtureTimestampMs + 1000,
|
|
71
|
+
}),
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
export async function createAdMobSsvConformanceFixture(input = {}) {
|
|
75
|
+
const { verifier } = await createAdMobSsvConformanceContext(input, {
|
|
76
|
+
includeSecp256k1Fixture: false,
|
|
77
|
+
});
|
|
78
|
+
return {
|
|
79
|
+
verifier,
|
|
80
|
+
placements,
|
|
81
|
+
firstRequest: rewardRequest('reward-1'),
|
|
82
|
+
replayRequest: rewardRequest('reward-2'),
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
export async function runAdMobSsvConformance(input = {}) {
|
|
86
|
+
const { callbackSource, publicKeySource, subtle, verifier, } = await createAdMobSsvConformanceContext(input, {
|
|
87
|
+
includeSecp256k1Fixture: true,
|
|
88
|
+
});
|
|
89
|
+
const firstRequest = rewardRequest('reward-1');
|
|
90
|
+
const firstDecision = await verifier.verifyAdReward(verificationInput(firstRequest));
|
|
91
|
+
assert(firstDecision.status === 'verified'
|
|
92
|
+
&& firstDecision.verificationId
|
|
93
|
+
=== 'admob:ssv:18fa792de1bca816048293fc71035638'
|
|
94
|
+
&& firstDecision.verifiedAt === '2026-07-16T00:00:00.000Z', 'a verified callback must emit the signed transaction authority identity');
|
|
95
|
+
const pending = await createAdMobSsvEvidenceVerifier({
|
|
96
|
+
callbackSource: mapCallbackSource(new Map()),
|
|
97
|
+
publicKeySource,
|
|
98
|
+
subtle,
|
|
99
|
+
now: () => fixtureTimestampMs + 1000,
|
|
100
|
+
}).verifyAdReward(verificationInput(firstRequest));
|
|
101
|
+
assertDecision(pending, 'pending', 'ADMOB_SSV_EVIDENCE_PENDING');
|
|
102
|
+
const tamperedCallback = fixtureCallback('reward-1', `${firstFixtureSignature.slice(0, -1)}S`);
|
|
103
|
+
const tampered = await createAdMobSsvEvidenceVerifier({
|
|
104
|
+
callbackSource: fixedCallbackSource(tamperedCallback),
|
|
105
|
+
publicKeySource,
|
|
106
|
+
subtle,
|
|
107
|
+
now: () => fixtureTimestampMs + 1000,
|
|
108
|
+
}).verifyAdReward(verificationInput(firstRequest));
|
|
109
|
+
assertDecision(tampered, 'rejected', 'ADMOB_SSV_SIGNATURE_INVALID');
|
|
110
|
+
const equivalentPercentEncoding = await createAdMobSsvEvidenceVerifier({
|
|
111
|
+
callbackSource: fixedCallbackSource(fixtureCallback('reward-1', firstFixtureSignature).replace('%7B', '%7b')),
|
|
112
|
+
publicKeySource,
|
|
113
|
+
subtle,
|
|
114
|
+
now: () => fixtureTimestampMs + 1000,
|
|
115
|
+
}).verifyAdReward(verificationInput(firstRequest));
|
|
116
|
+
assert(equivalentPercentEncoding.status === 'verified', 'equivalent percent-encoding must verify against AdMob-decoded query bytes');
|
|
117
|
+
const validCallback = fixtureCallback('reward-1', firstFixtureSignature);
|
|
118
|
+
const duplicateSignedField = await createAdMobSsvEvidenceVerifier({
|
|
119
|
+
callbackSource: fixedCallbackSource(validCallback.replace('&signature=', '&user_id=player-1&signature=')),
|
|
120
|
+
publicKeySource,
|
|
121
|
+
subtle,
|
|
122
|
+
now: () => fixtureTimestampMs + 1000,
|
|
123
|
+
}).verifyAdReward(verificationInput(firstRequest));
|
|
124
|
+
assertDecision(duplicateSignedField, 'rejected', 'ADMOB_SSV_CALLBACK_INVALID');
|
|
125
|
+
const missingSignedField = await createAdMobSsvEvidenceVerifier({
|
|
126
|
+
callbackSource: fixedCallbackSource(validCallback.replace('&user_id=player-1', '')),
|
|
127
|
+
publicKeySource,
|
|
128
|
+
subtle,
|
|
129
|
+
now: () => fixtureTimestampMs + 1000,
|
|
130
|
+
}).verifyAdReward(verificationInput(firstRequest));
|
|
131
|
+
assertDecision(missingSignedField, 'rejected', 'ADMOB_SSV_CALLBACK_INVALID');
|
|
132
|
+
const unknownKey = await createAdMobSsvEvidenceVerifier({
|
|
133
|
+
callbackSource: fixedCallbackSource(fixtureCallback('reward-1', firstFixtureSignature).replace(`key_id=${fixtureKeyId}`, 'key_id=9999999999')),
|
|
134
|
+
publicKeySource,
|
|
135
|
+
subtle,
|
|
136
|
+
now: () => fixtureTimestampMs + 1000,
|
|
137
|
+
}).verifyAdReward(verificationInput(firstRequest));
|
|
138
|
+
assertDecision(unknownKey, 'rejected', 'ADMOB_SSV_KEY_UNAVAILABLE');
|
|
139
|
+
const secp256k1Decision = await verifier.verifyAdReward(verificationInput(rewardRequest('reward-secp')));
|
|
140
|
+
assert(secp256k1Decision.status === 'verified'
|
|
141
|
+
&& secp256k1Decision.verificationId
|
|
142
|
+
=== `admob:ssv:${secp256k1FixtureTransactionId}`, 'a signed secp256k1 callback must verify when the key feed rotates curves');
|
|
143
|
+
const identityMismatch = await verifier.verifyAdReward(verificationInput({
|
|
144
|
+
...firstRequest,
|
|
145
|
+
playerId: 'different-player',
|
|
146
|
+
}));
|
|
147
|
+
assertDecision(identityMismatch, 'rejected', 'ADMOB_SSV_USER_MISMATCH');
|
|
148
|
+
const expired = await createAdMobSsvEvidenceVerifier({
|
|
149
|
+
callbackSource,
|
|
150
|
+
publicKeySource,
|
|
151
|
+
subtle,
|
|
152
|
+
now: () => fixtureTimestampMs + 86400001,
|
|
153
|
+
}).verifyAdReward(verificationInput(firstRequest));
|
|
154
|
+
assertDecision(expired, 'rejected', 'ADMOB_SSV_CALLBACK_EXPIRED');
|
|
155
|
+
const future = await createAdMobSsvEvidenceVerifier({
|
|
156
|
+
callbackSource,
|
|
157
|
+
publicKeySource,
|
|
158
|
+
subtle,
|
|
159
|
+
now: () => fixtureTimestampMs - 300001,
|
|
160
|
+
}).verifyAdReward(verificationInput(firstRequest));
|
|
161
|
+
assertDecision(future, 'rejected', 'ADMOB_SSV_TIMESTAMP_IN_FUTURE');
|
|
162
|
+
const ageBoundary = await createAdMobSsvEvidenceVerifier({
|
|
163
|
+
callbackSource,
|
|
164
|
+
publicKeySource,
|
|
165
|
+
subtle,
|
|
166
|
+
now: () => fixtureTimestampMs + 86400000,
|
|
167
|
+
}).verifyAdReward(verificationInput(firstRequest));
|
|
168
|
+
assert(ageBoundary.status === 'verified', 'the maximum callback age boundary must remain valid');
|
|
169
|
+
const futureSkewBoundary = await createAdMobSsvEvidenceVerifier({
|
|
170
|
+
callbackSource,
|
|
171
|
+
publicKeySource,
|
|
172
|
+
subtle,
|
|
173
|
+
now: () => fixtureTimestampMs - 300000,
|
|
174
|
+
}).verifyAdReward(verificationInput(firstRequest));
|
|
175
|
+
assert(futureSkewBoundary.status === 'verified', 'the maximum future skew boundary must remain valid');
|
|
176
|
+
const sharedTransactionDecision = await verifier.verifyAdReward(verificationInput(rewardRequest('reward-2')));
|
|
177
|
+
assert(sharedTransactionDecision.status === 'verified'
|
|
178
|
+
&& firstDecision.status === 'verified'
|
|
179
|
+
&& sharedTransactionDecision.verificationId === firstDecision.verificationId, 'callbacks sharing a signed transaction must preserve one ledger authority identity');
|
|
180
|
+
return {
|
|
181
|
+
checks: adMobSsvConformanceChecks,
|
|
182
|
+
passed: true,
|
|
183
|
+
};
|
|
184
|
+
}
|
|
185
|
+
function verificationInput(request) {
|
|
186
|
+
return {
|
|
187
|
+
request,
|
|
188
|
+
placement,
|
|
189
|
+
platformPlacementId: placement.platformPlacementIds.android,
|
|
190
|
+
signal: new AbortController().signal,
|
|
191
|
+
timeoutMs: 10000,
|
|
192
|
+
};
|
|
193
|
+
}
|
|
194
|
+
function rewardRequest(idempotencyKey) {
|
|
195
|
+
return {
|
|
196
|
+
target: 'android',
|
|
197
|
+
playerId: 'player-1',
|
|
198
|
+
placementId: 'CONTINUE_AFTER_FAIL',
|
|
199
|
+
idempotencyKey,
|
|
200
|
+
completedAt: '2026-07-16T00:00:01.000Z',
|
|
201
|
+
};
|
|
202
|
+
}
|
|
203
|
+
function fixtureCallback(idempotencyKey, signature, input = {}) {
|
|
204
|
+
const customData = encodeURIComponent(JSON.stringify({
|
|
205
|
+
schema: 'mpgd.admob.ssv.binding.v1',
|
|
206
|
+
playerId: 'player-1',
|
|
207
|
+
placementId: 'CONTINUE_AFTER_FAIL',
|
|
208
|
+
idempotencyKey,
|
|
209
|
+
}));
|
|
210
|
+
const query = [
|
|
211
|
+
'ad_network=5450213213286189855',
|
|
212
|
+
'ad_unit=reward_continue',
|
|
213
|
+
`custom_data=${customData}`,
|
|
214
|
+
'reward_amount=1',
|
|
215
|
+
'reward_item=continue',
|
|
216
|
+
`timestamp=${String(fixtureTimestampMs)}`,
|
|
217
|
+
`transaction_id=${input.transactionId ?? fixtureTransactionId}`,
|
|
218
|
+
'user_id=player-1',
|
|
219
|
+
].join('&');
|
|
220
|
+
return `https://game.example.test/admob/ssv?${query}&signature=${signature}&key_id=${input.keyId ?? fixtureKeyId}`;
|
|
221
|
+
}
|
|
222
|
+
function mapCallbackSource(callbacks) {
|
|
223
|
+
return {
|
|
224
|
+
async findCallback({ request }) {
|
|
225
|
+
return callbacks.get(request.idempotencyKey);
|
|
226
|
+
},
|
|
227
|
+
};
|
|
228
|
+
}
|
|
229
|
+
function fixedCallbackSource(callback) {
|
|
230
|
+
return {
|
|
231
|
+
async findCallback() {
|
|
232
|
+
return callback;
|
|
233
|
+
},
|
|
234
|
+
};
|
|
235
|
+
}
|
|
236
|
+
function fixedPublicKeySource(publicKeys) {
|
|
237
|
+
return {
|
|
238
|
+
async getPublicKey({ keyId }) {
|
|
239
|
+
return publicKeys.get(keyId);
|
|
240
|
+
},
|
|
241
|
+
};
|
|
242
|
+
}
|
|
243
|
+
function assertDecision(decision, status, reason) {
|
|
244
|
+
const receivedReason = decision.status === 'verified' ? undefined : decision.reason;
|
|
245
|
+
assert(decision.status === status && receivedReason === reason, `expected ${status}/${reason}, received ${decision.status}/${String(receivedReason)}`);
|
|
246
|
+
}
|
|
247
|
+
function assert(condition, message) {
|
|
248
|
+
if (!condition) {
|
|
249
|
+
throw new Error(`AdMob SSV conformance failed: ${message}.`);
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
function readGlobalSubtleCrypto() {
|
|
253
|
+
const subtle = globalThis.crypto?.subtle;
|
|
254
|
+
if (subtle === undefined) {
|
|
255
|
+
throw new Error('AdMob SSV conformance requires Web Crypto SubtleCrypto.');
|
|
256
|
+
}
|
|
257
|
+
return subtle;
|
|
258
|
+
}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import type { AdPlacementEntry } from '@mpgd/catalog';
|
|
2
|
+
import type { GameServicesEvidenceVerifier } from './evidence-verification';
|
|
3
|
+
import type { ClaimAdRewardRequest } from './types';
|
|
4
|
+
export declare const admobSsvCustomDataSchema = "mpgd.admob.ssv.binding.v1";
|
|
5
|
+
export declare const defaultAdMobSsvMaximumCallbackAgeMs = 86400000;
|
|
6
|
+
export declare const defaultAdMobSsvMaximumFutureSkewMs = 300000;
|
|
7
|
+
export interface AdMobSsvCustomDataBinding {
|
|
8
|
+
readonly playerId: string;
|
|
9
|
+
readonly placementId: string;
|
|
10
|
+
readonly idempotencyKey: string;
|
|
11
|
+
}
|
|
12
|
+
export interface AdMobSsvCallbackLookupInput {
|
|
13
|
+
readonly request: ClaimAdRewardRequest;
|
|
14
|
+
readonly platformPlacementId: string;
|
|
15
|
+
readonly signal: AbortSignal;
|
|
16
|
+
}
|
|
17
|
+
export interface AdMobSsvCallbackSource {
|
|
18
|
+
findCallback(input: AdMobSsvCallbackLookupInput): Promise<string | undefined>;
|
|
19
|
+
}
|
|
20
|
+
export interface AdMobSsvPublicKeyLookupInput {
|
|
21
|
+
readonly keyId: string;
|
|
22
|
+
readonly signal: AbortSignal;
|
|
23
|
+
}
|
|
24
|
+
export interface AdMobSsvSecp256k1PublicKey {
|
|
25
|
+
readonly kind: 'secp256k1';
|
|
26
|
+
readonly publicKey: Uint8Array<ArrayBuffer>;
|
|
27
|
+
}
|
|
28
|
+
export type AdMobSsvPublicKey = CryptoKey | AdMobSsvSecp256k1PublicKey;
|
|
29
|
+
export interface AdMobSsvPublicKeySource {
|
|
30
|
+
getPublicKey(input: AdMobSsvPublicKeyLookupInput): Promise<AdMobSsvPublicKey | undefined>;
|
|
31
|
+
}
|
|
32
|
+
export interface ResolveAdMobSsvAdUnitInput {
|
|
33
|
+
readonly request: ClaimAdRewardRequest;
|
|
34
|
+
readonly placement: AdPlacementEntry;
|
|
35
|
+
readonly platformPlacementId: string;
|
|
36
|
+
}
|
|
37
|
+
export interface ResolveAdMobSsvRewardItemInput {
|
|
38
|
+
readonly request: ClaimAdRewardRequest;
|
|
39
|
+
readonly placement: AdPlacementEntry;
|
|
40
|
+
}
|
|
41
|
+
export interface CreateAdMobSsvEvidenceVerifierInput {
|
|
42
|
+
readonly callbackSource: AdMobSsvCallbackSource;
|
|
43
|
+
readonly publicKeySource: AdMobSsvPublicKeySource;
|
|
44
|
+
readonly subtle?: SubtleCrypto;
|
|
45
|
+
readonly now?: () => number;
|
|
46
|
+
readonly maximumCallbackAgeMs?: number;
|
|
47
|
+
readonly maximumFutureSkewMs?: number;
|
|
48
|
+
readonly resolveAdUnit?: (input: ResolveAdMobSsvAdUnitInput) => string;
|
|
49
|
+
readonly resolveRewardItem?: (input: ResolveAdMobSsvRewardItemInput) => string;
|
|
50
|
+
}
|
|
51
|
+
export declare function encodeAdMobSsvCustomData(input: AdMobSsvCustomDataBinding): string;
|
|
52
|
+
export declare function decodeAdMobSsvCustomData(input: string): AdMobSsvCustomDataBinding | undefined;
|
|
53
|
+
export declare function importAdMobSsvPublicKey(base64Spki: string, subtle?: SubtleCrypto): Promise<AdMobSsvPublicKey>;
|
|
54
|
+
export declare function createAdMobSsvEvidenceVerifier(input: CreateAdMobSsvEvidenceVerifierInput): GameServicesEvidenceVerifier;
|