Skip to content

Commit b88cf74

Browse files
stalniycloud-j-luna
authored andcommitted
refactor: changes JWT signing alg to ES256KADR36 (#110)
1 parent 0d97965 commit b88cf74

File tree

13 files changed

+100
-230
lines changed

13 files changed

+100
-230
lines changed

go/cli/context.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ func QueryClientFromContext(ctx context.Context) (aclient.QueryClient, error) {
5353

5454
res, valid := val.(aclient.QueryClient)
5555
if !valid {
56-
return nil, fmt.Errorf("invalid context value, expected \"aclient.Client\", actual \"%s\"", reflect.TypeOf(val))
56+
return nil, fmt.Errorf("invalid context value, expected \"aclient.QueryClient\", actual \"%s\"", reflect.TypeOf(val))
5757
}
5858

5959
return res, nil

ts/README.md

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -100,13 +100,12 @@ This is the recommended method for getting authorized access to your resources o
100100
**Generating a JWT Token**
101101

102102
```ts
103-
import { DirectSecp256k1HdWallet } from "@cosmjs/proto-signing";
104-
import { JwtTokenManager, createSignArbitraryAkashWallet } from "@akashnetwork/chain-sdk"
103+
import { Secp256k1HdWallet } from "@cosmjs/amino";
104+
import { JwtTokenManager } from "@akashnetwork/chain-sdk"
105105

106-
const wallet = await DirectSecp256k1HdWallet.fromMnemonic(mnemonic, { prefix: "akash" });
106+
const wallet = await Secp256k1HdWallet.fromMnemonic(mnemonic, { prefix: "akash" });
107107
const accounts = await wallet.getAccounts();
108-
const signer = await createSignArbitraryAkashWallet(wallet);
109-
const tokenManager = new JwtTokenManager(signer);
108+
const tokenManager = new JwtTokenManager(wallet);
110109

111110
// See https://akash.network/roadmap/aep-64/ for details
112111
const token = await tokenManager.generateToken({

ts/package-lock.json

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

ts/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@
6060
"@cosmjs/math": "^0.33.1",
6161
"@cosmjs/proto-signing": "^0.33.1",
6262
"@cosmjs/stargate": "^0.33.1",
63+
"base64-js": "^1.5.1",
6364
"js-yaml": "^4.1.0",
6465
"json-stable-stringify": "^1.3.0",
6566
"jsrsasign": "^11.1.0",

ts/src/generated/protos/akash/base/offchain/sign/v1/sign.ts

Lines changed: 0 additions & 144 deletions
This file was deleted.

ts/src/sdk/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,4 @@ export * from "./index.shared.ts";
22
export { createChainNodeSDK, type ChainNodeSDKOptions } from "./chain/createChainNodeSDK.ts";
33
export { createProviderSDK, type ProviderSDKOptions } from "./provider/createProviderSDK.ts";
44
export { certificateManager, CertificateManager, type CertificateInfo, type CertificatePem, type ValidityRangeOptions } from "./provider/auth/mtls/index.ts";
5-
export { JwtTokenManager, type CreateJWTOptions, type JwtTokenPayload, type JwtValidationResult, createSignArbitraryAkashWallet, type SignArbitraryAkashWallet } from "./provider/auth/jwt/index.ts";
5+
export * from "./provider/auth/jwt/index.ts";

ts/src/sdk/index.web.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
export * from "./index.shared.ts";
22
export { createChainNodeWebSDK, type ChainNodeWebSDKOptions } from "./chain/createChainNodeWebSDK.ts";
33
export { certificateManager, CertificateManager, type CertificateInfo, type CertificatePem, type ValidityRangeOptions } from "./provider/auth/mtls/index.ts";
4-
export { JwtTokenManager, type CreateJWTOptions, type JwtTokenPayload, type JwtValidationResult, type SignArbitraryAkashWallet } from "./provider/auth/jwt/index.ts";
4+
export * from "./provider/auth/jwt/index.ts";

ts/src/sdk/provider/auth/jwt/base64.ts

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
1+
import { fromByteArray } from "base64-js";
2+
13
export function base64UrlEncode(value: string | Uint8Array): string {
2-
const str = typeof value === "string" ? value : String.fromCharCode(...value);
3-
const base64 = btoa(str);
4-
return toBase64Url(base64);
4+
return toBase64Url(base64Encode(value));
55
}
66

77
/**
@@ -11,13 +11,14 @@ export function toBase64Url(base64Encoded: string): string {
1111
return base64Encoded.replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
1212
}
1313

14+
const textDecoder = new TextDecoder();
1415
export function base64UrlDecode(value: string): string {
1516
let str = value;
1617
// Convert from base64url → base64
1718
str = str.replace(/-/g, "+").replace(/_/g, "/");
1819
str = str.padEnd(str.length + (4 - (str.length % 4)) % 4, "=");
1920

20-
return new TextDecoder().decode(Uint8Array.from(atob(str), (c) => c.charCodeAt(0)));
21+
return textDecoder.decode(Uint8Array.from(atob(str), (c) => c.charCodeAt(0)));
2122
}
2223

2324
/**
@@ -29,3 +30,9 @@ export function base64Decode(base64String: string): Record<string, unknown> {
2930
const decoded = atob(base64String);
3031
return JSON.parse(decoded);
3132
}
33+
34+
const textEncoder = new TextEncoder();
35+
export function base64Encode(value: string | Uint8Array): string {
36+
const data = typeof value === "string" ? textEncoder.encode(value) : value;
37+
return fromByteArray(data);
38+
}
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
export { JwtTokenManager, type CreateJWTOptions } from "./jwt-token.ts";
22
export type { JwtTokenPayload, AccessScope as JwtTokenAccessScope, LeasePermission } from "./types.ts";
33
export { JwtValidator, type JwtValidationResult } from "./jwt-validator.ts";
4-
export { createSignArbitraryAkashWallet, type SignArbitraryAkashWallet } from "./wallet-utils.ts";
4+
export { type OfflineDataSigner } from "./wallet-utils.ts";

ts/src/sdk/provider/auth/jwt/jwt-token.spec.ts

Lines changed: 19 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
import { DirectSecp256k1HdWallet } from "@cosmjs/proto-signing";
1+
import { Secp256k1HdWallet } from "@cosmjs/amino";
2+
import type { AccountData } from "@cosmjs/proto-signing";
23
import { beforeAll, describe, expect, it } from "@jest/globals";
34
import fs from "fs";
45
import path from "path";
@@ -8,28 +9,29 @@ import type { CreateJWTOptions } from "./jwt-token.ts";
89
import { JwtTokenManager } from "./jwt-token.ts";
910
import type { ClaimsTestCase, SigningTestCase } from "./test/test-utils.ts";
1011
import { replaceTemplateValues } from "./test/test-utils.ts";
11-
import { createSignArbitraryAkashWallet, type SignArbitraryAkashWallet } from "./wallet-utils.ts";
12+
import { createOfflineDataSigner } from "./wallet-utils.ts";
1213

1314
describe("JWT Claims Validation", () => {
1415
const testdataPath = path.join(__dirname, "../../../../../..", "testdata", "jwt");
1516
const jwtMnemonic = fs.readFileSync(path.join(testdataPath, "mnemonic"), "utf-8").trim();
1617
const jwtSigningTestCases = JSON.parse(fs.readFileSync(path.join(testdataPath, "cases_es256k.json"), "utf-8")) as SigningTestCase[];
1718
const jwtClaimsTestCases = JSON.parse(fs.readFileSync(path.join(testdataPath, "cases_jwt.json.tmpl"), "utf-8")) as ClaimsTestCase[];
1819

19-
let testWallet: DirectSecp256k1HdWallet;
20+
let testWallet: Secp256k1HdWallet;
2021
let jwtToken: JwtTokenManager;
21-
let akashWallet: SignArbitraryAkashWallet;
22+
let testAccount: AccountData;
2223

2324
beforeAll(async () => {
24-
testWallet = await DirectSecp256k1HdWallet.fromMnemonic(jwtMnemonic, {
25+
testWallet = await Secp256k1HdWallet.fromMnemonic(jwtMnemonic, {
2526
prefix: "akash",
2627
});
27-
akashWallet = await createSignArbitraryAkashWallet(testWallet);
28-
jwtToken = new JwtTokenManager(akashWallet);
28+
const [account] = await testWallet.getAccounts();
29+
testAccount = account;
30+
jwtToken = new JwtTokenManager(testWallet);
2931
});
3032

31-
it.each(jwtClaimsTestCases)("$description", async (testCase) => {
32-
const { claims, tokenString } = replaceTemplateValues(testCase);
33+
it.each(jwtClaimsTestCases.filter(isSigningWithES256KADR36))("$description", async (testCase) => {
34+
const { claims, tokenString } = replaceTemplateValues(testCase, { iss: testAccount.address });
3335

3436
// For test cases that should fail, we need to validate the payload first
3537
if (testCase.expected.signFail || testCase.expected.verifyFail) {
@@ -54,16 +56,17 @@ describe("JWT Claims Validation", () => {
5456
}
5557
});
5658

57-
it.each(jwtSigningTestCases)("$description", async (testCase) => {
59+
it.each(jwtSigningTestCases.filter(isSigningWithES256KADR36))("$description", async (testCase) => {
5860
const [expectedHeader, expectedPayload, expectedSignature] = testCase.tokenString.split(".");
5961
expect(expectedHeader).toBeDefined();
6062
expect(expectedPayload).toBeDefined();
6163
expect(expectedSignature).toBeDefined();
6264

6365
const signingString = `${expectedHeader}.${expectedPayload}`;
6466

65-
// Sign using the mock wallet's signArbitrary method
66-
const signResponse = await akashWallet.signArbitrary(akashWallet.address, signingString);
67+
const signer = createOfflineDataSigner(testWallet);
68+
const [account] = await testWallet.getAccounts();
69+
const signResponse = await signer.signArbitrary(account.address, signingString);
6770
const signature = toBase64Url(signResponse.signature);
6871

6972
if (!testCase.mustFail) {
@@ -72,4 +75,8 @@ describe("JWT Claims Validation", () => {
7275
expect(signature).not.toBe(expectedSignature);
7376
}
7477
});
78+
79+
function isSigningWithES256KADR36(testCase: SigningTestCase | ClaimsTestCase): boolean {
80+
return !testCase.expected.alg || testCase.expected.alg === "ES256KADR36";
81+
}
7582
});

0 commit comments

Comments
 (0)