@youkno/edge-cli 1.21.25 → 1.21.26
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/commands/wallet.js +138 -0
- package/dist/index.js +2 -0
- package/package.json +1 -1
- package/src/commands/wallet.ts +128 -0
- package/src/index.ts +2 -0
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.registerWallet = registerWallet;
|
|
37
|
+
const crypto = __importStar(require("crypto"));
|
|
38
|
+
const fs = __importStar(require("fs"));
|
|
39
|
+
const path = __importStar(require("path"));
|
|
40
|
+
const GOOGLE_TOKEN_URL = "https://oauth2.googleapis.com/token";
|
|
41
|
+
const GOOGLE_WALLET_SCOPE = "https://www.googleapis.com/auth/wallet_object.issuer";
|
|
42
|
+
const GOOGLE_ISSUER_API = "https://walletobjects.googleapis.com/walletobjects/v1/issuer";
|
|
43
|
+
function signJwt(payload, privateKey) {
|
|
44
|
+
const header = Buffer.from(JSON.stringify({ alg: "RS256", typ: "JWT" })).toString("base64url");
|
|
45
|
+
const body = Buffer.from(JSON.stringify(payload)).toString("base64url");
|
|
46
|
+
const signature = crypto.sign("sha256", Buffer.from(`${header}.${body}`), privateKey).toString("base64url");
|
|
47
|
+
return `${header}.${body}.${signature}`;
|
|
48
|
+
}
|
|
49
|
+
async function getAccessToken(serviceAccountJson) {
|
|
50
|
+
const sa = JSON.parse(serviceAccountJson);
|
|
51
|
+
const now = Math.floor(Date.now() / 1000);
|
|
52
|
+
const assertion = signJwt({
|
|
53
|
+
iss: sa.client_email,
|
|
54
|
+
scope: GOOGLE_WALLET_SCOPE,
|
|
55
|
+
aud: GOOGLE_TOKEN_URL,
|
|
56
|
+
iat: now,
|
|
57
|
+
exp: now + 3600,
|
|
58
|
+
}, sa.private_key);
|
|
59
|
+
const res = await fetch(GOOGLE_TOKEN_URL, {
|
|
60
|
+
method: "POST",
|
|
61
|
+
headers: { "Content-Type": "application/x-www-form-urlencoded" },
|
|
62
|
+
body: `grant_type=urn:ietf:params:oauth:grant-type:jwt-bearer&assertion=${assertion}`,
|
|
63
|
+
});
|
|
64
|
+
if (!res.ok) {
|
|
65
|
+
const text = await res.text();
|
|
66
|
+
throw new Error(`Failed to get access token: ${res.status} ${text}`);
|
|
67
|
+
}
|
|
68
|
+
const data = (await res.json());
|
|
69
|
+
return data.access_token;
|
|
70
|
+
}
|
|
71
|
+
async function getIssuer(token, issuerId) {
|
|
72
|
+
const res = await fetch(`${GOOGLE_ISSUER_API}/${issuerId}`, {
|
|
73
|
+
headers: { Authorization: `Bearer ${token}` },
|
|
74
|
+
});
|
|
75
|
+
if (!res.ok) {
|
|
76
|
+
const text = await res.text();
|
|
77
|
+
throw new Error(`Failed to get issuer: ${res.status} ${text}`);
|
|
78
|
+
}
|
|
79
|
+
return (await res.json());
|
|
80
|
+
}
|
|
81
|
+
async function updateIssuer(token, issuer, callbackUrl) {
|
|
82
|
+
const body = {
|
|
83
|
+
...issuer,
|
|
84
|
+
callbackOptions: { url: callbackUrl },
|
|
85
|
+
};
|
|
86
|
+
const res = await fetch(`${GOOGLE_ISSUER_API}/${issuer.issuerId}`, {
|
|
87
|
+
method: "PUT",
|
|
88
|
+
headers: {
|
|
89
|
+
Authorization: `Bearer ${token}`,
|
|
90
|
+
"Content-Type": "application/json",
|
|
91
|
+
},
|
|
92
|
+
body: JSON.stringify(body),
|
|
93
|
+
});
|
|
94
|
+
if (!res.ok) {
|
|
95
|
+
const text = await res.text();
|
|
96
|
+
throw new Error(`Failed to update issuer: ${res.status} ${text}`);
|
|
97
|
+
}
|
|
98
|
+
return (await res.json());
|
|
99
|
+
}
|
|
100
|
+
function registerWallet(program) {
|
|
101
|
+
const wallet = program.command("wallet").description("Google Wallet management commands");
|
|
102
|
+
wallet
|
|
103
|
+
.command("google:set-callback")
|
|
104
|
+
.description("Set the Google Wallet issuer callback URL")
|
|
105
|
+
.requiredOption("--issuer-id <id>", "Google Wallet issuer ID")
|
|
106
|
+
.requiredOption("--callback-url <url>", "Callback URL for save/del events")
|
|
107
|
+
.requiredOption("--key-file <path>", "Path to Google service account JSON key file")
|
|
108
|
+
.action(async (opts) => {
|
|
109
|
+
const keyPath = path.resolve(opts.keyFile);
|
|
110
|
+
if (!fs.existsSync(keyPath)) {
|
|
111
|
+
throw new Error(`Key file not found: ${keyPath}`);
|
|
112
|
+
}
|
|
113
|
+
const saJson = fs.readFileSync(keyPath, "utf-8");
|
|
114
|
+
process.stdout.write(`Authenticating as service account...\n`);
|
|
115
|
+
const token = await getAccessToken(saJson);
|
|
116
|
+
process.stdout.write(`Fetching issuer ${opts.issuerId}...\n`);
|
|
117
|
+
const issuer = await getIssuer(token, opts.issuerId);
|
|
118
|
+
process.stdout.write(`Setting callback URL: ${opts.callbackUrl}\n`);
|
|
119
|
+
const updated = await updateIssuer(token, issuer, opts.callbackUrl);
|
|
120
|
+
process.stdout.write(`Done. Issuer updated:\n`);
|
|
121
|
+
process.stdout.write(`${JSON.stringify(updated, null, 2)}\n`);
|
|
122
|
+
});
|
|
123
|
+
wallet
|
|
124
|
+
.command("google:get-issuer")
|
|
125
|
+
.description("Show current Google Wallet issuer configuration")
|
|
126
|
+
.requiredOption("--issuer-id <id>", "Google Wallet issuer ID")
|
|
127
|
+
.requiredOption("--key-file <path>", "Path to Google service account JSON key file")
|
|
128
|
+
.action(async (opts) => {
|
|
129
|
+
const keyPath = path.resolve(opts.keyFile);
|
|
130
|
+
if (!fs.existsSync(keyPath)) {
|
|
131
|
+
throw new Error(`Key file not found: ${keyPath}`);
|
|
132
|
+
}
|
|
133
|
+
const saJson = fs.readFileSync(keyPath, "utf-8");
|
|
134
|
+
const token = await getAccessToken(saJson);
|
|
135
|
+
const issuer = await getIssuer(token, opts.issuerId);
|
|
136
|
+
process.stdout.write(`${JSON.stringify(issuer, null, 2)}\n`);
|
|
137
|
+
});
|
|
138
|
+
}
|
package/dist/index.js
CHANGED
|
@@ -9,6 +9,7 @@ const product_1 = require("./commands/product");
|
|
|
9
9
|
const shell_1 = require("./commands/shell");
|
|
10
10
|
const token_1 = require("./commands/token");
|
|
11
11
|
const uploadUsers_1 = require("./commands/uploadUsers");
|
|
12
|
+
const wallet_1 = require("./commands/wallet");
|
|
12
13
|
const program = new commander_1.Command();
|
|
13
14
|
program
|
|
14
15
|
.name("edge-cli")
|
|
@@ -33,6 +34,7 @@ program
|
|
|
33
34
|
(0, token_1.registerToken)(program);
|
|
34
35
|
(0, shell_1.registerShell)(program);
|
|
35
36
|
(0, uploadUsers_1.registerUploadUsers)(program);
|
|
37
|
+
(0, wallet_1.registerWallet)(program);
|
|
36
38
|
program.parseAsync(process.argv).catch((error) => {
|
|
37
39
|
process.stderr.write(`ERROR: ${error instanceof Error ? error.message : String(error)}\n`);
|
|
38
40
|
process.exit(1);
|
package/package.json
CHANGED
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
import { Command } from "commander";
|
|
2
|
+
import * as crypto from "crypto";
|
|
3
|
+
import * as fs from "fs";
|
|
4
|
+
import * as path from "path";
|
|
5
|
+
|
|
6
|
+
const GOOGLE_TOKEN_URL = "https://oauth2.googleapis.com/token";
|
|
7
|
+
const GOOGLE_WALLET_SCOPE = "https://www.googleapis.com/auth/wallet_object.issuer";
|
|
8
|
+
const GOOGLE_ISSUER_API = "https://walletobjects.googleapis.com/walletobjects/v1/issuer";
|
|
9
|
+
|
|
10
|
+
function signJwt(payload: Record<string, unknown>, privateKey: string): string {
|
|
11
|
+
const header = Buffer.from(JSON.stringify({ alg: "RS256", typ: "JWT" })).toString("base64url");
|
|
12
|
+
const body = Buffer.from(JSON.stringify(payload)).toString("base64url");
|
|
13
|
+
const signature = crypto.sign("sha256", Buffer.from(`${header}.${body}`), privateKey).toString("base64url");
|
|
14
|
+
return `${header}.${body}.${signature}`;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
async function getAccessToken(serviceAccountJson: string): Promise<string> {
|
|
18
|
+
const sa = JSON.parse(serviceAccountJson);
|
|
19
|
+
const now = Math.floor(Date.now() / 1000);
|
|
20
|
+
const assertion = signJwt(
|
|
21
|
+
{
|
|
22
|
+
iss: sa.client_email,
|
|
23
|
+
scope: GOOGLE_WALLET_SCOPE,
|
|
24
|
+
aud: GOOGLE_TOKEN_URL,
|
|
25
|
+
iat: now,
|
|
26
|
+
exp: now + 3600,
|
|
27
|
+
},
|
|
28
|
+
sa.private_key,
|
|
29
|
+
);
|
|
30
|
+
|
|
31
|
+
const res = await fetch(GOOGLE_TOKEN_URL, {
|
|
32
|
+
method: "POST",
|
|
33
|
+
headers: { "Content-Type": "application/x-www-form-urlencoded" },
|
|
34
|
+
body: `grant_type=urn:ietf:params:oauth:grant-type:jwt-bearer&assertion=${assertion}`,
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
if (!res.ok) {
|
|
38
|
+
const text = await res.text();
|
|
39
|
+
throw new Error(`Failed to get access token: ${res.status} ${text}`);
|
|
40
|
+
}
|
|
41
|
+
const data = (await res.json()) as { access_token: string };
|
|
42
|
+
return data.access_token;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
async function getIssuer(token: string, issuerId: string): Promise<Record<string, unknown>> {
|
|
46
|
+
const res = await fetch(`${GOOGLE_ISSUER_API}/${issuerId}`, {
|
|
47
|
+
headers: { Authorization: `Bearer ${token}` },
|
|
48
|
+
});
|
|
49
|
+
if (!res.ok) {
|
|
50
|
+
const text = await res.text();
|
|
51
|
+
throw new Error(`Failed to get issuer: ${res.status} ${text}`);
|
|
52
|
+
}
|
|
53
|
+
return (await res.json()) as Record<string, unknown>;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
async function updateIssuer(
|
|
57
|
+
token: string,
|
|
58
|
+
issuer: Record<string, unknown>,
|
|
59
|
+
callbackUrl: string,
|
|
60
|
+
): Promise<Record<string, unknown>> {
|
|
61
|
+
const body = {
|
|
62
|
+
...issuer,
|
|
63
|
+
callbackOptions: { url: callbackUrl },
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
const res = await fetch(`${GOOGLE_ISSUER_API}/${issuer.issuerId}`, {
|
|
67
|
+
method: "PUT",
|
|
68
|
+
headers: {
|
|
69
|
+
Authorization: `Bearer ${token}`,
|
|
70
|
+
"Content-Type": "application/json",
|
|
71
|
+
},
|
|
72
|
+
body: JSON.stringify(body),
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
if (!res.ok) {
|
|
76
|
+
const text = await res.text();
|
|
77
|
+
throw new Error(`Failed to update issuer: ${res.status} ${text}`);
|
|
78
|
+
}
|
|
79
|
+
return (await res.json()) as Record<string, unknown>;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
export function registerWallet(program: Command): void {
|
|
83
|
+
const wallet = program.command("wallet").description("Google Wallet management commands");
|
|
84
|
+
|
|
85
|
+
wallet
|
|
86
|
+
.command("google:set-callback")
|
|
87
|
+
.description("Set the Google Wallet issuer callback URL")
|
|
88
|
+
.requiredOption("--issuer-id <id>", "Google Wallet issuer ID")
|
|
89
|
+
.requiredOption("--callback-url <url>", "Callback URL for save/del events")
|
|
90
|
+
.requiredOption("--key-file <path>", "Path to Google service account JSON key file")
|
|
91
|
+
.action(async (opts: { issuerId: string; callbackUrl: string; keyFile: string }) => {
|
|
92
|
+
const keyPath = path.resolve(opts.keyFile);
|
|
93
|
+
if (!fs.existsSync(keyPath)) {
|
|
94
|
+
throw new Error(`Key file not found: ${keyPath}`);
|
|
95
|
+
}
|
|
96
|
+
const saJson = fs.readFileSync(keyPath, "utf-8");
|
|
97
|
+
|
|
98
|
+
process.stdout.write(`Authenticating as service account...\n`);
|
|
99
|
+
const token = await getAccessToken(saJson);
|
|
100
|
+
|
|
101
|
+
process.stdout.write(`Fetching issuer ${opts.issuerId}...\n`);
|
|
102
|
+
const issuer = await getIssuer(token, opts.issuerId);
|
|
103
|
+
|
|
104
|
+
process.stdout.write(`Setting callback URL: ${opts.callbackUrl}\n`);
|
|
105
|
+
const updated = await updateIssuer(token, issuer, opts.callbackUrl);
|
|
106
|
+
|
|
107
|
+
process.stdout.write(`Done. Issuer updated:\n`);
|
|
108
|
+
process.stdout.write(`${JSON.stringify(updated, null, 2)}\n`);
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
wallet
|
|
112
|
+
.command("google:get-issuer")
|
|
113
|
+
.description("Show current Google Wallet issuer configuration")
|
|
114
|
+
.requiredOption("--issuer-id <id>", "Google Wallet issuer ID")
|
|
115
|
+
.requiredOption("--key-file <path>", "Path to Google service account JSON key file")
|
|
116
|
+
.action(async (opts: { issuerId: string; keyFile: string }) => {
|
|
117
|
+
const keyPath = path.resolve(opts.keyFile);
|
|
118
|
+
if (!fs.existsSync(keyPath)) {
|
|
119
|
+
throw new Error(`Key file not found: ${keyPath}`);
|
|
120
|
+
}
|
|
121
|
+
const saJson = fs.readFileSync(keyPath, "utf-8");
|
|
122
|
+
|
|
123
|
+
const token = await getAccessToken(saJson);
|
|
124
|
+
const issuer = await getIssuer(token, opts.issuerId);
|
|
125
|
+
|
|
126
|
+
process.stdout.write(`${JSON.stringify(issuer, null, 2)}\n`);
|
|
127
|
+
});
|
|
128
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -9,6 +9,7 @@ import { registerProduct } from "./commands/product";
|
|
|
9
9
|
import { registerShell } from "./commands/shell";
|
|
10
10
|
import { registerToken } from "./commands/token";
|
|
11
11
|
import { registerUploadUsers } from "./commands/uploadUsers";
|
|
12
|
+
import { registerWallet } from "./commands/wallet";
|
|
12
13
|
import { CliEnv } from "./lib/types";
|
|
13
14
|
|
|
14
15
|
const program = new Command();
|
|
@@ -37,6 +38,7 @@ registerLogin(program);
|
|
|
37
38
|
registerToken(program);
|
|
38
39
|
registerShell(program);
|
|
39
40
|
registerUploadUsers(program);
|
|
41
|
+
registerWallet(program);
|
|
40
42
|
|
|
41
43
|
program.parseAsync(process.argv).catch((error) => {
|
|
42
44
|
process.stderr.write(`ERROR: ${error instanceof Error ? error.message : String(error)}\n`);
|