Skip to content

Commit 48f1793

Browse files
authored
Merge pull request #69 from cruxprotocol/feature/cruxpay-prefix
add walletClientName as prefix to all Gaia files mandatorily.
2 parents 9f26017 + 1b72187 commit 48f1793

File tree

9 files changed

+61
-86
lines changed

9 files changed

+61
-86
lines changed

src/packages/configuration-service.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -142,7 +142,7 @@ export class BlockstackConfigurationService extends NameServiceConfigurationServ
142142
domain: this.clientName + identityUtils.CRUX_DOMAIN_SUFFIX,
143143
subdomain: CONFIG_SUBDOMAIN,
144144
}).toString();
145-
return await getContentFromGaiaHub(blockstackId, nameservice.UPLOADABLE_JSON_FILES.CLIENT_CONFIG, config.BLOCKSTACK.BNS_NODES, this.clientName);
145+
return await getContentFromGaiaHub(blockstackId, `${this.clientName}_${nameservice.UPLOADABLE_JSON_FILES.CLIENT_CONFIG}`, config.BLOCKSTACK.BNS_NODES);
146146
}
147147

148148
private _getClientAssetMapping = async (): Promise<IClientAssetMapping> => {

src/packages/error/error-string.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,9 +27,9 @@ export const ERROR_STRINGS = {
2727
[PackageErrorCode.GaiaCruxPayUploadFailed]: "Unable to upload '{0}' to gaia: '{1}'",
2828
[PackageErrorCode.GaiaEmptyResponse]: "Gaia sent empty response",
2929
[PackageErrorCode.GetAddressMapFailed]: "No address found for CRUX ID",
30-
[PackageErrorCode.GaiaCruxPayGetFailed]: "Unable to get gaia read url prefix: '{0}'",
31-
[PackageErrorCode.GaiaClientConfigGetFailed]: "Unable to get gaia read url prefix: '{0}'",
32-
[PackageErrorCode.GaiaGetFileFailed]: "Unable to get gaia read url prefix: '{0}'",
30+
[PackageErrorCode.GaiaCruxPayGetFailed]: "Unable to get from gaia: '{0}'",
31+
[PackageErrorCode.GaiaClientConfigGetFailed]: "Unable to get from gaia : '{0}'",
32+
[PackageErrorCode.GaiaGetFileFailed]: "Unable to get gaia file: '{0}'",
3333
[PackageErrorCode.GaiaProfileUploadFailed]: "Unable to upload '{0}' to gaia: '{1}'",
3434
[PackageErrorCode.GaiaUploadFailed]: "Unable to upload '{0}' to gaia: '{1}'",
3535
[PackageErrorCode.GetNamesByAddressFailed]: "'{0}' failed with error '{1}'",

src/packages/gaia-service/index.ts

Lines changed: 3 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import * as blockstack from "blockstack";
22
import { SECP256K1Client, TokenSigner } from "jsontokens";
33
import { getLogger } from "../..";
4-
import { ErrorHelper, PackageErrorCode } from "../error";
4+
import { ErrorHelper } from "../error";
55
import * as nameservice from "../name-service/blockstack-service";
66
import { UPLOADABLE_JSON_FILES } from "../name-service/blockstack-service";
77
import { sanitizePrivKey } from "../utils";
@@ -15,46 +15,13 @@ export class GaiaService {
1515
this.gaiaWriteUrl = gaiaWriteUrl;
1616
}
1717

18-
public uploadContentToGaiaHub = async (filename: UPLOADABLE_JSON_FILES, privKey: string, content: any, prefix?: string, type = "application/json"): Promise<string> => {
18+
public uploadContentToGaiaHub = async (filename: string, privKey: string, content: any, type = "application/json"): Promise<string> => {
1919
const sanitizedPrivKey = sanitizePrivKey(privKey);
2020
const hubURL = this.gaiaWriteUrl;
2121
const hubConfig = await blockstack.connectToGaiaHub(hubURL, sanitizedPrivKey);
2222
const tokenFile = this._generateTokenFileForContent(sanitizedPrivKey, content);
2323
const contentToUpload: string = JSON.stringify(tokenFile);
24-
let finalURL: string;
25-
try {
26-
finalURL = await blockstack.uploadToGaiaHub((prefix ? `${prefix}_` : "") + filename, contentToUpload, hubConfig, type);
27-
log.debug(`finalUrl is ${finalURL}`);
28-
} catch (error) {
29-
const packageErrorCode = nameservice.BlockstackService.getUploadPackageErrorCodeForFilename(filename);
30-
throw ErrorHelper.getPackageError(packageErrorCode, filename, error);
31-
}
32-
return finalURL;
33-
}
34-
35-
public uploadProfileInfo = async (privKey: string): Promise<void> => {
36-
// TODO: validate the privateKey format and convert
37-
privKey = sanitizePrivKey(privKey);
38-
39-
const hubUrl = this.gaiaWriteUrl;
40-
const hubConfig = await blockstack.connectToGaiaHub(hubUrl, privKey);
41-
const profileObj = {
42-
"@context": "http://schema.org/",
43-
"@type": "Person",
44-
};
45-
const filename = UPLOADABLE_JSON_FILES.PROFILE;
46-
const person = new blockstack.Person(profileObj);
47-
const token = person.toToken(privKey);
48-
log.debug(token);
49-
const tokenFile = [blockstack.wrapProfileToken(token)];
50-
log.debug(tokenFile);
51-
try {
52-
const finalUrl = await blockstack.uploadToGaiaHub(filename, JSON.stringify(tokenFile), hubConfig, "application/json");
53-
log.debug(finalUrl);
54-
} catch (error) {
55-
throw ErrorHelper.getPackageError(PackageErrorCode.GaiaProfileUploadFailed, filename, error);
56-
}
57-
return;
24+
return await blockstack.uploadToGaiaHub(filename, contentToUpload, hubConfig, type);
5825
}
5926

6027
private _generateTokenFileForContent(privateKey: string, content: any) {

src/packages/gaia-service/utils.ts

Lines changed: 5 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -13,28 +13,20 @@ interface gaiaData {
1313
ownerAddress: string;
1414
}
1515

16-
export const getContentFromGaiaHub = async (blockstackId: string, filename: nameservice.UPLOADABLE_JSON_FILES, bnsNodes: string[], prefix?: string): Promise<any> => {
17-
let fileUrl: string;
16+
export const getContentFromGaiaHub = async (blockstackId: string, filename: string, bnsNodes: string[]): Promise<any> => {
1817
const gaiaDetails = await getGaiaDataFromBlockstackID(blockstackId, bnsNodes);
19-
fileUrl = gaiaDetails.gaiaReadUrl + gaiaDetails.ownerAddress + "/" + (prefix ? `${prefix}_` : "") + filename;
18+
const fileUrl = gaiaDetails.gaiaReadUrl + gaiaDetails.ownerAddress + "/" + filename;
2019
const options = {
2120
json: true,
2221
method: "GET",
2322
url: fileUrl,
2423
};
2524

2625
let finalContent: any;
27-
let responseBody: any;
2826
const cacheTTL = filename === nameservice.UPLOADABLE_JSON_FILES.CLIENT_CONFIG ? 3600 : undefined;
29-
try {
30-
responseBody = await cachedFunctionCall(options.url, cacheTTL, httpJSONRequest, [options], async (data) => {
31-
return Boolean(filename !== nameservice.UPLOADABLE_JSON_FILES.CLIENT_CONFIG || data.indexOf("BlobNotFound") > 0 || data.indexOf("NoSuchKey") > 0);
32-
});
33-
log.debug(`Response from ${filename}`, responseBody);
34-
} catch (error) {
35-
const packageErrorCode = nameservice.BlockstackService.getGetPackageErrorCodeForFilename(filename);
36-
throw ErrorHelper.getPackageError(packageErrorCode, filename, error);
37-
}
27+
const responseBody: any = await cachedFunctionCall(options.url, cacheTTL, httpJSONRequest, [options], async (data) => {
28+
return Boolean(filename !== nameservice.UPLOADABLE_JSON_FILES.CLIENT_CONFIG || data.indexOf("BlobNotFound") > 0 || data.indexOf("NoSuchKey") > 0);
29+
});
3830
if (responseBody.indexOf("BlobNotFound") > 0 || responseBody.indexOf("NoSuchKey") > 0) {
3931
throw ErrorHelper.getPackageError(PackageErrorCode.GaiaEmptyResponse);
4032
} else {

src/packages/identity-utils.ts

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -97,12 +97,18 @@ export class BlockstackId {
9797
}
9898

9999
export class IdTranslator {
100+
public static cruxDomainToBlockstackDomain = (domain: string): string => {
101+
return domain + CRUX_DOMAIN_SUFFIX;
102+
}
103+
public static blockstackDomainToCruxDomain = (domain: string): string => {
104+
return domain.slice(0, -5);
105+
}
100106
public static cruxToBlockstack = (cruxId: CruxId): BlockstackId => {
101107
if (cruxId.components.namespace !== DEFAULT_CRUX_NAMESPACE) {
102108
throw ErrorHelper.getPackageError(PackageErrorCode.CruxIdNamespaceValidation, cruxId.components.namespace);
103109
}
104110
return new BlockstackId({
105-
domain: cruxId.components.domain + CRUX_DOMAIN_SUFFIX,
111+
domain: IdTranslator.cruxDomainToBlockstackDomain(cruxId.components.domain),
106112
subdomain: cruxId.components.subdomain,
107113
});
108114
}
@@ -116,7 +122,7 @@ export class IdTranslator {
116122
if (!bsId.components.domain.endsWith(CRUX_DOMAIN_SUFFIX)) {
117123
throw ErrorHelper.getPackageError(PackageErrorCode.BlockstackIdInvalidDomainForTranslation);
118124
}
119-
const cruxDomain = bsId.components.domain.slice(0, -5);
125+
const cruxDomain = IdTranslator.blockstackDomainToCruxDomain(bsId.components.domain);
120126

121127
return new CruxId({
122128
domain: cruxDomain,

src/packages/name-service/blockstack-service.ts

Lines changed: 33 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import config from "../../config";
88
import { Encryption } from "../encryption";
99
import {CruxClientError, ErrorHelper, PackageErrorCode} from "../error";
1010

11+
import { PackageError } from "../error/package-error";
1112
import { GaiaService } from "../gaia-service";
1213
import { getContentFromGaiaHub } from "../gaia-service/utils";
1314
import {BlockstackId, CruxId, IdTranslator} from "../identity-utils";
@@ -83,7 +84,6 @@ const defaultBNSConfig: IDefaultServiceOptions = {
8384
export enum UPLOADABLE_JSON_FILES {
8485
CRUXPAY = "cruxpay.json",
8586
CLIENT_CONFIG = "client-config.json",
86-
PROFILE = "profile.json",
8787
}
8888

8989
export class BlockstackService extends nameService.NameService {
@@ -186,8 +186,6 @@ export class BlockstackService extends nameService.NameService {
186186
throw ErrorHelper.getPackageError(PackageErrorCode.CouldNotFindKeyPairToRegisterName);
187187
}
188188

189-
await this._gaiaService.uploadProfileInfo(identityKeyPair.privKey);
190-
191189
const registeredSubdomain = await this._registerSubdomain(subdomain, identityKeyPair.address);
192190
this._identityCouple = getIdentityCoupleFromBlockstackId(new BlockstackId({
193191
domain: this._domain,
@@ -265,14 +263,14 @@ export class BlockstackService extends nameService.NameService {
265263
} catch (error) {
266264
throw ErrorHelper.getPackageError(PackageErrorCode.AddressMappingDecodingFailure);
267265
}
268-
await this._gaiaService.uploadContentToGaiaHub(UPLOADABLE_JSON_FILES.CRUXPAY, identityClaim.secrets.identityKeyPair.privKey, addressMapping);
266+
await this._uploadContentToGaiaHub(UPLOADABLE_JSON_FILES.CRUXPAY, identityClaim.secrets.identityKeyPair.privKey, addressMapping, IdTranslator.blockstackDomainToCruxDomain(this._domain));
269267
return;
270268
}
271269

272270
public getAddressMapping = async (fullCruxId: string): Promise<IAddressMapping> => {
273271
const cruxId = CruxId.fromString(fullCruxId);
274272
const blockstackIdString = IdTranslator.cruxToBlockstack(cruxId).toString();
275-
return await getContentFromGaiaHub(blockstackIdString, UPLOADABLE_JSON_FILES.CRUXPAY, this._bnsNodes);
273+
return await this._getContentFromGaiaHub(blockstackIdString, UPLOADABLE_JSON_FILES.CRUXPAY, this._bnsNodes, cruxId.components.domain);
276274
}
277275

278276
private _getConfigOptions = (defaultConfig: IDefaultServiceOptions, options: IBlockstackServiceInputOptions): IBlockstackServiceOptions => {
@@ -370,4 +368,34 @@ export class BlockstackService extends nameService.NameService {
370368
}
371369
return status;
372370
}
371+
372+
private _uploadContentToGaiaHub = async (filename: UPLOADABLE_JSON_FILES, privKey: string, content: any, prefix: string): Promise<string> => {
373+
const filenameToUpload = `${prefix}_${filename}`;
374+
let finalURL: string;
375+
try {
376+
finalURL = await this._gaiaService.uploadContentToGaiaHub(filenameToUpload, privKey, content, prefix);
377+
log.debug(`finalUrl is ${finalURL}`);
378+
} catch (error) {
379+
const packageErrorCode = BlockstackService.getUploadPackageErrorCodeForFilename(filename);
380+
throw ErrorHelper.getPackageError(packageErrorCode, filename, error);
381+
}
382+
return finalURL;
383+
}
384+
385+
private _getContentFromGaiaHub = async (blockstackId: string, filename: UPLOADABLE_JSON_FILES, bnsNodes: string[], prefix: string): Promise<any> => {
386+
const filenameToFetch = `${prefix}_${filename}`;
387+
let responseBody: any;
388+
try {
389+
responseBody = await getContentFromGaiaHub(blockstackId, filenameToFetch, bnsNodes);
390+
log.debug(`Response from ${filenameToFetch}`, responseBody);
391+
} catch (error) {
392+
if (error instanceof PackageError && error.errorCode) {
393+
throw error;
394+
} else {
395+
const packageErrorCode = BlockstackService.getGetPackageErrorCodeForFilename(filename);
396+
throw ErrorHelper.getPackageError(packageErrorCode, filename, error);
397+
}
398+
}
399+
return responseBody;
400+
}
373401
}

src/test/gaia-service-utils.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -48,13 +48,13 @@ describe('getContentFromGaiaHub tests', () => {
4848
raisedError = error
4949
}
5050
expect(httpJSONRequestStub.callCount).to.be.equal(3)
51-
expect(raisedError.errorCode).to.be.equal(errors.PackageErrorCode.GaiaClientConfigGetFailed)
51+
expect(raisedError).is.not.undefined
5252
});
5353
it('given token and public key, if blockstack validation fails, throws "TokenVerificationFailed"', async() => {
5454
let raisedError
5555
verifyProfileTokenStub.throws("sample exception")
5656
try {
57-
await getContentFromGaiaHub('cs1.devcoinswitch_crux.id', UPLOADABLE_JSON_FILES.CRUXPAY, config.BLOCKSTACK.BNS_NODES)
57+
await getContentFromGaiaHub('cs1.devcoinswitch_crux.id', "devcoinswitch_" + UPLOADABLE_JSON_FILES.CRUXPAY, config.BLOCKSTACK.BNS_NODES)
5858
} catch (error) {
5959
raisedError = error
6060
}
@@ -67,7 +67,7 @@ describe('getContentFromGaiaHub tests', () => {
6767
let raisedError
6868
publicKeyToAddressStub.resolves("some address")
6969
try {
70-
await getContentFromGaiaHub('cs1.devcoinswitch_crux.id', UPLOADABLE_JSON_FILES.CRUXPAY, config.BLOCKSTACK.BNS_NODES)
70+
await getContentFromGaiaHub('cs1.devcoinswitch_crux.id', "devcoinswitch_" + UPLOADABLE_JSON_FILES.CRUXPAY, config.BLOCKSTACK.BNS_NODES)
7171
} catch (error) {
7272
raisedError = error
7373
}

src/test/nameservice.ts

Lines changed: 4 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -433,17 +433,6 @@ describe('BlockstackService tests', () => {
433433
json: true,
434434
strictSSL: false
435435
}
436-
it('if uploadToGaiaHub breaks, should raise "GaiaProfileUploadFailed"', async () => {
437-
uploadToGaiaHubStub.onCall(0).throws('unhandled in mocks')
438-
let raisedError
439-
try {
440-
await blkstkService.registerName(sampleIdentityClaim, sampleSubdomain)
441-
} catch (error) {
442-
raisedError = error
443-
}
444-
expect(raisedError.errorCode).to.be.equal(errors.PackageErrorCode.GaiaProfileUploadFailed)
445-
expect(uploadToGaiaHubStub.calledOnce).is.true
446-
})
447436

448437
it('given valid identityClaim and a non-registered cruxId (bob@devcoinswitch.crux), should successfully register and return the fullCruxId', async () => {
449438
let registeredName = await blkstkService.registerName(sampleIdentityClaim, desiredName)
@@ -453,16 +442,13 @@ describe('BlockstackService tests', () => {
453442
expect(registeredName).is.equal(expectedRegisteredName)
454443
})
455444
it('given valid identityClaim and a registered cruxId, should throw "SubdomainRegistrationFailed"', async () => {
456-
uploadToGaiaHubStub.resolves("https://gaia.cruxpay.com/1HtFkbXFWHFW5Kd4GLfiRqkffS5KLZ91eJ/cruxpay.json")
457445
let raisedError
458446
try {
459447
await blkstkService.registerName(sampleIdentityClaim, sampleSubdomain)
460448
} catch (error) {
461449
raisedError = error
462450
}
463-
expect(uploadToGaiaHubStub.calledOnce).is.true
464-
// expect(httpJSONRequestStub.calledOnce).is.true
465-
expect(uploadToGaiaHubStub.calledWith('profile.json')).is.true
451+
expect(httpJSONRequestStub.calledOnce).is.true
466452
expect(httpJSONRequestStub.calledWith(redundantRegistrarRequestOptions)).is.true
467453
expect(raisedError.errorCode).to.be.equal(errors.PackageErrorCode.SubdomainRegistrationFailed)
468454
})
@@ -492,7 +478,7 @@ describe('BlockstackService tests', () => {
492478
it('given valid identityClaim and valid addressMap, should resolve the promise without errors', async () => {
493479
// mocked values
494480
connectToGaiaHubStub.resolves({ "url_prefix": "https://gaia.cruxpay.com/", "address": "1HtFkbXFWHFW5Kd4GLfiRqkffS5KLZ91eJ", "token": "v1:eyJ0eXAiOiJKV1QiLCJhbGciOiJFUzI1NksifQ.eyJnYWlhQ2hhbGxlbmdlIjoiW1wiZ2FpYWh1YlwiLFwiMFwiLFwic3RvcmFnZTIuYmxvY2tzdGFjay5vcmdcIixcImJsb2Nrc3RhY2tfc3RvcmFnZV9wbGVhc2Vfc2lnblwiXSIsImh1YlVybCI6Imh0dHBzOi8vaHViLmJsb2Nrc3RhY2sub3JnIiwiaXNzIjoiMDJiYzljM2Y4ZTkyNGI3ZGU5MjEyY2ViZDAxMjlmMWJlMmU2YzNmMjkwNGU5MTFiMzA2OThiZGU3N2JlNDg3OGI4Iiwic2FsdCI6ImE0ODk1ZWE1ZjdjZjI2N2VhNDEwMjg2ZjRjNzk4MTY3In0.QFuEEVijDYMKHjERaPA_YXwnwWoBq8iVg4pzEusP0S_u5jSmmxqeJcumyMK8cqT4NTmOYgnMUC4u4-9OAUWOIQ", "server": "https://hub.cruxpay.com" })
495-
uploadToGaiaHubStub.resolves("https://gaia.cruxpay.com/1HtFkbXFWHFW5Kd4GLfiRqkffS5KLZ91eJ/cruxpay.json")
481+
uploadToGaiaHubStub.resolves("https://gaia.cruxpay.com/1HtFkbXFWHFW5Kd4GLfiRqkffS5KLZ91eJ/devcoinswitch_cruxpay.json")
496482

497483
// initialising the nameservice
498484
let bs = new blockstackService.BlockstackService(nameservice_options)
@@ -561,7 +547,7 @@ describe('BlockstackService tests', () => {
561547
url: '/v1/names/cs1.devcoinswitch_crux.id',
562548
json: true
563549
}
564-
let gaiaRequestOptions = { method: "GET", url: "https://gaia.cruxpay.com/1HtFkbXFWHFW5Kd4GLfiRqkffS5KLZ91eJ/cruxpay.json", json: true }
550+
let gaiaRequestOptions = { method: "GET", url: "https://gaia.cruxpay.com/1HtFkbXFWHFW5Kd4GLfiRqkffS5KLZ91eJ/devcoinswitch_cruxpay.json", json: true }
565551

566552
it('given registered cruxId (sanchay@devcoinswitch.crux), which does not have pulic addressMap should throw "GaiaCruxPayGetFailed"', async () => {
567553
let raisedError
@@ -591,7 +577,7 @@ describe('BlockstackService tests', () => {
591577
expect(raisedError.errorCode).to.be.equal(errors.PackageErrorCode.UserDoesNotExist)
592578
})
593579
it('given registered cruxId, which has not made addresses public, should throw "GaiaEmptyResponse"', async() => {
594-
let gaiaRequestOptions = { method: "GET", url: "https://gaia.cruxpay.com/1HtFkbXFWHFW5Kd4GLfiRqkffS5KLZ91eJ/cruxpay.json", json: true }
580+
let gaiaRequestOptions = { method: "GET", url: "https://gaia.cruxpay.com/1HtFkbXFWHFW5Kd4GLfiRqkffS5KLZ91eJ/devcoinswitch_cruxpay.json", json: true }
595581
let response = "<Error><Code>BlobNotFound</Code><Message>The specified blob does not exist.RequestId:299c4c0b-701e-0066-67df-7d085b000000Time:2019-10-08T13:54:51.8653868Z</Message></Error>"
596582
httpJSONRequestStub.withArgs(gaiaRequestOptions).returns(response)
597583
let raisedError
@@ -608,16 +594,12 @@ describe('BlockstackService tests', () => {
608594
it("given filename, returns upload package error code", async() => {
609595
let fileNameCruxPay = UPLOADABLE_JSON_FILES.CRUXPAY
610596
let fileNameClientConfig = UPLOADABLE_JSON_FILES.CLIENT_CONFIG
611-
let fileNameProfile = UPLOADABLE_JSON_FILES.PROFILE
612597

613598
let cruxPayStatus = blockstackService.BlockstackService.getUploadPackageErrorCodeForFilename(fileNameCruxPay)
614599
expect(cruxPayStatus).to.be.equal(errors.PackageErrorCode.GaiaCruxPayUploadFailed)
615600

616601
let clientConfigPayStatus = blockstackService.BlockstackService.getUploadPackageErrorCodeForFilename(fileNameClientConfig)
617602
expect(clientConfigPayStatus).to.be.equal(errors.PackageErrorCode.GaiaClientConfigUploadFailed)
618-
619-
let profileStatus = blockstackService.BlockstackService.getUploadPackageErrorCodeForFilename(fileNameProfile)
620-
expect(profileStatus).to.be.equal(errors.PackageErrorCode.GaiaUploadFailed)
621603
})
622604
})
623605

src/test/requestMocks/nameservice-reqmocks.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -202,7 +202,7 @@ let requestResponseArray: { request: object, response: any }[] = [
202202
}
203203
},
204204
{
205-
request: { method: "GET", url: "https://gaia.cruxpay.com/1HtFkbXFWHFW5Kd4GLfiRqkffS5KLZ91eJ/cruxpay.json", json: true },
205+
request: { method: "GET", url: "https://gaia.cruxpay.com/1HtFkbXFWHFW5Kd4GLfiRqkffS5KLZ91eJ/devcoinswitch_cruxpay.json", json: true },
206206
response: [{ "token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJFUzI1NksifQ.eyJpc3N1ZXIiOnsicHVibGljS2V5IjoiMDJiYzljM2Y4ZTkyNGI3ZGU5MjEyY2ViZDAxMjlmMWJlMmU2YzNmMjkwNGU5MTFiMzA2OThiZGU3N2JlNDg3OGI4In0sInN1YmplY3QiOnsicHVibGljS2V5IjoiMDJiYzljM2Y4ZTkyNGI3ZGU5MjEyY2ViZDAxMjlmMWJlMmU2YzNmMjkwNGU5MTFiMzA2OThiZGU3N2JlNDg3OGI4In0sImNsYWltIjp7IkJUQyI6eyJhZGRyZXNzSGFzaCI6IjFIdEZrYlhGV0hGVzVLZDRHTGZpUnFrZmZTNUtMWjkxZUoifX19.U9Uxw8fNDZn-6Fe9tkzIeB3Tl97pSe8SJIwTmcJyUlOKFxzq1Sqy2KIwNQAhTrzIh9Ue9AGNWTlSh-w8zUOnWA", "decodedToken": { "header": { "typ": "JWT", "alg": "ES256K" }, "payload": { "issuer": { "publicKey": "02bc9c3f8e924b7de9212cebd0129f1be2e6c3f2904e911b30698bde77be4878b8" }, "subject": { "publicKey": "02bc9c3f8e924b7de9212cebd0129f1be2e6c3f2904e911b30698bde77be4878b8" }, "claim": { "BTC": { "addressHash": "1HtFkbXFWHFW5Kd4GLfiRqkffS5KLZ91eJ" } } }, "signature": "U9Uxw8fNDZn-6Fe9tkzIeB3Tl97pSe8SJIwTmcJyUlOKFxzq1Sqy2KIwNQAhTrzIh9Ue9AGNWTlSh-w8zUOnWA" } }]
207207
},
208208
{

0 commit comments

Comments
 (0)