agc-api-cli 1.0.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/README.md +109 -0
- package/dist/chunk-CSXIZ7GI.mjs +411 -0
- package/dist/chunk-CSXIZ7GI.mjs.map +1 -0
- package/dist/cli.d.mts +1 -0
- package/dist/cli.d.ts +1 -0
- package/dist/cli.js +981 -0
- package/dist/cli.js.map +1 -0
- package/dist/cli.mjs +562 -0
- package/dist/cli.mjs.map +1 -0
- package/dist/index.d.mts +347 -0
- package/dist/index.d.ts +347 -0
- package/dist/index.js +455 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +17 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +35 -0
package/dist/cli.mjs
ADDED
|
@@ -0,0 +1,562 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
AuthManager,
|
|
4
|
+
ProvisionService,
|
|
5
|
+
PublishService,
|
|
6
|
+
UploadService,
|
|
7
|
+
agcClient
|
|
8
|
+
} from "./chunk-CSXIZ7GI.mjs";
|
|
9
|
+
|
|
10
|
+
// src/cli/index.ts
|
|
11
|
+
import { Command } from "commander";
|
|
12
|
+
import * as fs3 from "fs";
|
|
13
|
+
|
|
14
|
+
// src/services/domain.ts
|
|
15
|
+
import fs from "fs";
|
|
16
|
+
var DomainService = class {
|
|
17
|
+
/**
|
|
18
|
+
* 查询元服务的域名配置信息
|
|
19
|
+
*/
|
|
20
|
+
static async queryDomain(req) {
|
|
21
|
+
const response = await agcClient.get(
|
|
22
|
+
"/api/dms/domain-manage/v1/app/domain",
|
|
23
|
+
{
|
|
24
|
+
params: { category: req.category },
|
|
25
|
+
headers: { appId: req.appId }
|
|
26
|
+
}
|
|
27
|
+
);
|
|
28
|
+
return response.data;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* 新增/更新元服务的域名配置信息
|
|
32
|
+
*/
|
|
33
|
+
static async updateDomain(req) {
|
|
34
|
+
const response = await agcClient.post(
|
|
35
|
+
"/api/dms/domain-manage/v1/app/domain",
|
|
36
|
+
{ domains: req.domains },
|
|
37
|
+
{
|
|
38
|
+
params: { category: req.category },
|
|
39
|
+
headers: { appId: req.appId }
|
|
40
|
+
}
|
|
41
|
+
);
|
|
42
|
+
return response.data;
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* 查询域名修改次数/配置上限
|
|
46
|
+
*/
|
|
47
|
+
static async queryDomainConfig(req) {
|
|
48
|
+
const response = await agcClient.get(
|
|
49
|
+
"/api/dms/domain-manage/v1/app/domain/config",
|
|
50
|
+
{
|
|
51
|
+
params: { appId: req.appId }
|
|
52
|
+
}
|
|
53
|
+
);
|
|
54
|
+
return response.data;
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* 下载域名配置文件
|
|
58
|
+
*/
|
|
59
|
+
static async verifyFile(req, outputPath) {
|
|
60
|
+
const response = await agcClient.get(
|
|
61
|
+
"/api/dms/domain-manage/v1/app/domain/verify-file",
|
|
62
|
+
{
|
|
63
|
+
headers: { appId: req.appId },
|
|
64
|
+
responseType: "stream"
|
|
65
|
+
}
|
|
66
|
+
);
|
|
67
|
+
return new Promise((resolve, reject) => {
|
|
68
|
+
const writer = fs.createWriteStream(outputPath);
|
|
69
|
+
response.data.pipe(writer);
|
|
70
|
+
let error = null;
|
|
71
|
+
writer.on("error", (err) => {
|
|
72
|
+
error = err;
|
|
73
|
+
writer.close();
|
|
74
|
+
reject(err);
|
|
75
|
+
});
|
|
76
|
+
writer.on("close", () => {
|
|
77
|
+
if (!error) {
|
|
78
|
+
resolve();
|
|
79
|
+
}
|
|
80
|
+
});
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* 预检查业务域名配置
|
|
85
|
+
*/
|
|
86
|
+
static async preCheckDomain(req) {
|
|
87
|
+
const response = await agcClient.post(
|
|
88
|
+
"/api/dms/domain-manage/v1/app/domain/pre-check",
|
|
89
|
+
{ domain: req.domain },
|
|
90
|
+
{
|
|
91
|
+
headers: { appId: req.appId }
|
|
92
|
+
}
|
|
93
|
+
);
|
|
94
|
+
return response.data;
|
|
95
|
+
}
|
|
96
|
+
};
|
|
97
|
+
|
|
98
|
+
// src/services/sign.ts
|
|
99
|
+
import fs2 from "fs";
|
|
100
|
+
import path from "path";
|
|
101
|
+
import { execFileSync } from "child_process";
|
|
102
|
+
import crypto from "crypto";
|
|
103
|
+
var SignService = class {
|
|
104
|
+
static async createSignP12AndCsr(options) {
|
|
105
|
+
const outDir = options.outDir ? path.resolve(options.outDir) : path.join(process.cwd(), "sign_keys");
|
|
106
|
+
if (!fs2.existsSync(outDir)) {
|
|
107
|
+
fs2.mkdirSync(outDir, { recursive: true });
|
|
108
|
+
}
|
|
109
|
+
const filename = options.filename || this.createSignDefaultFilename();
|
|
110
|
+
const p12FilePath = path.join(outDir, `${filename}.p12`);
|
|
111
|
+
const csrFilePath = path.join(outDir, `${filename}.csr`);
|
|
112
|
+
const javaPath = options.javaPath || "java";
|
|
113
|
+
const sdkPath = options.sdkPath || process.env.HARMONYOS_SDK_PATH;
|
|
114
|
+
if (!sdkPath) {
|
|
115
|
+
throw new Error("sdkPath is required. Provide it via --sdk-path or HARMONYOS_SDK_PATH env var.");
|
|
116
|
+
}
|
|
117
|
+
const signToolPath = path.join(sdkPath, "default", "openharmony", "toolchains", "lib", "hap-sign-tool.jar");
|
|
118
|
+
if (!fs2.existsSync(signToolPath)) {
|
|
119
|
+
throw new Error(`hap-sign-tool.jar not found at ${signToolPath}`);
|
|
120
|
+
}
|
|
121
|
+
const alias = options.alias;
|
|
122
|
+
const pwd = options.pwd || "123456";
|
|
123
|
+
this.doCreateSignFileP12(javaPath, signToolPath, alias, pwd, p12FilePath);
|
|
124
|
+
this.doCreateSignFileCsr(javaPath, signToolPath, alias, pwd, p12FilePath, csrFilePath);
|
|
125
|
+
const csrContent = fs2.readFileSync(csrFilePath, "utf8");
|
|
126
|
+
const cerPath = path.join(outDir, `${filename}.cer`);
|
|
127
|
+
const p7bPath = path.join(outDir, `${filename}.p7b`);
|
|
128
|
+
return {
|
|
129
|
+
alias,
|
|
130
|
+
p12Path: p12FilePath,
|
|
131
|
+
csrPath: csrFilePath,
|
|
132
|
+
csrContent,
|
|
133
|
+
storePath: outDir,
|
|
134
|
+
cerPath,
|
|
135
|
+
p7bPath
|
|
136
|
+
};
|
|
137
|
+
}
|
|
138
|
+
static createSignDefaultFilename() {
|
|
139
|
+
const timestamp = Date.now().toString();
|
|
140
|
+
const substring = timestamp.substring(timestamp.length - 5);
|
|
141
|
+
const randomString = crypto.randomInt(100, 1e3);
|
|
142
|
+
return `agc-cli-${substring}-${randomString}`;
|
|
143
|
+
}
|
|
144
|
+
static doCreateSignFileP12(javaPath, signToolPath, alias, pwd, outFilePath) {
|
|
145
|
+
const args = [
|
|
146
|
+
"-jar",
|
|
147
|
+
signToolPath,
|
|
148
|
+
"generate-keypair",
|
|
149
|
+
"-keyAlias",
|
|
150
|
+
alias,
|
|
151
|
+
"-keyPwd",
|
|
152
|
+
pwd,
|
|
153
|
+
"-keyAlg",
|
|
154
|
+
"ECC",
|
|
155
|
+
"-keySize",
|
|
156
|
+
"NIST-P-256",
|
|
157
|
+
"-keystoreFile",
|
|
158
|
+
outFilePath,
|
|
159
|
+
"-keystorePwd",
|
|
160
|
+
pwd
|
|
161
|
+
];
|
|
162
|
+
console.log(`Executing: ${javaPath} ${args.join(" ")}`);
|
|
163
|
+
execFileSync(javaPath, args, { stdio: "inherit" });
|
|
164
|
+
}
|
|
165
|
+
static doCreateSignFileCsr(javaPath, signToolPath, alias, pwd, p12Path, outFilePath) {
|
|
166
|
+
const args = [
|
|
167
|
+
"-jar",
|
|
168
|
+
signToolPath,
|
|
169
|
+
"generate-csr",
|
|
170
|
+
"-keyAlias",
|
|
171
|
+
alias,
|
|
172
|
+
"-keyPwd",
|
|
173
|
+
pwd,
|
|
174
|
+
"-subject",
|
|
175
|
+
"C=CN,O=OpenHarmony,OU=OpenHarmony Community,CN=App Release",
|
|
176
|
+
"-signAlg",
|
|
177
|
+
"SHA256withECDSA",
|
|
178
|
+
"-keystoreFile",
|
|
179
|
+
p12Path,
|
|
180
|
+
"-keystorePwd",
|
|
181
|
+
pwd,
|
|
182
|
+
"-outFile",
|
|
183
|
+
outFilePath
|
|
184
|
+
];
|
|
185
|
+
console.log(`Executing: ${javaPath} ${args.join(" ")}`);
|
|
186
|
+
execFileSync(javaPath, args, { stdio: "inherit" });
|
|
187
|
+
}
|
|
188
|
+
static COMPONENT = new Int8Array([49, 243, 9, 115, 214, 175, 91, 184, 211, 190, 177, 88, 101, 131, 192, 119]);
|
|
189
|
+
static readDirBytes(dirPath) {
|
|
190
|
+
const entries = fs2.readdirSync(dirPath).filter((f) => f !== ".DS_Store");
|
|
191
|
+
return new Int8Array(fs2.readFileSync(path.resolve(dirPath, entries[0])));
|
|
192
|
+
}
|
|
193
|
+
static readFd(materialPath) {
|
|
194
|
+
const fdDir = path.resolve(materialPath, "fd");
|
|
195
|
+
return fs2.readdirSync(fdDir).filter((f) => f !== ".DS_Store").map((e) => this.readDirBytes(path.resolve(fdDir, e)));
|
|
196
|
+
}
|
|
197
|
+
static xorBuffers(a, b) {
|
|
198
|
+
const result = new Int8Array(a.byteLength);
|
|
199
|
+
for (let i = 0; i < a.byteLength; i++) result[i] = a[i] ^ b[i];
|
|
200
|
+
return result;
|
|
201
|
+
}
|
|
202
|
+
static xorAll(components) {
|
|
203
|
+
let result = this.xorBuffers(components[0], components[1]);
|
|
204
|
+
for (let i = 2; i < components.length; i++) result = this.xorBuffers(result, components[i]);
|
|
205
|
+
return Buffer.from(result);
|
|
206
|
+
}
|
|
207
|
+
static aesDecrypt(key, data) {
|
|
208
|
+
const d = Buffer.from(data);
|
|
209
|
+
const tagLen = (255 & d[0]) << 24 | (255 & d[1]) << 16 | (255 & d[2]) << 8 | 255 & d[3];
|
|
210
|
+
const ivLen = d.length - 4 - tagLen;
|
|
211
|
+
const iv = d.subarray(4, 4 + ivLen);
|
|
212
|
+
const decipher = crypto.createDecipheriv("aes-128-gcm", key, iv);
|
|
213
|
+
decipher.setAuthTag(d.subarray(d.length - 16));
|
|
214
|
+
return Buffer.concat([decipher.update(d.subarray(4 + ivLen, d.length - 16)), decipher.final()]);
|
|
215
|
+
}
|
|
216
|
+
static aesEncrypt(key, plaintext) {
|
|
217
|
+
const iv = crypto.randomBytes(12);
|
|
218
|
+
const cipher = crypto.createCipheriv("aes-128-gcm", key, iv);
|
|
219
|
+
const enc = Buffer.concat([cipher.update(plaintext, "utf-8"), cipher.final()]);
|
|
220
|
+
const tag = cipher.getAuthTag();
|
|
221
|
+
const header = Buffer.alloc(4);
|
|
222
|
+
header.writeUInt32BE(enc.length + 16, 0);
|
|
223
|
+
return Buffer.concat([header, iv, enc, tag]).toString("hex").toUpperCase();
|
|
224
|
+
}
|
|
225
|
+
static deriveEncryptionKey(configDir) {
|
|
226
|
+
const materialDir = path.resolve(configDir, "material");
|
|
227
|
+
const fd = this.readFd(materialDir);
|
|
228
|
+
const salt = this.readDirBytes(path.resolve(materialDir, "ac"));
|
|
229
|
+
const rawKey = new Int8Array(
|
|
230
|
+
crypto.pbkdf2Sync(this.xorAll(fd.concat(this.COMPONENT)).toString(), salt, 1e4, 16, "sha256")
|
|
231
|
+
);
|
|
232
|
+
return new Int8Array(this.aesDecrypt(rawKey, this.readDirBytes(path.resolve(materialDir, "ce"))));
|
|
233
|
+
}
|
|
234
|
+
/**
|
|
235
|
+
* 使用 DevEco Studio 的加密密钥对密码进行 AES-128-GCM 加密,
|
|
236
|
+
* 生成 build-profile.json5 中 signingConfigs 所需的加密密码。
|
|
237
|
+
*/
|
|
238
|
+
static encryptPassword(password, configDir) {
|
|
239
|
+
const dir = configDir || path.join(process.env.HOME || "", ".ohos", "config");
|
|
240
|
+
if (!fs2.existsSync(path.resolve(dir, "material"))) {
|
|
241
|
+
throw new Error(`\u672A\u627E\u5230\u52A0\u5BC6\u5BC6\u94A5\u76EE\u5F55: ${path.resolve(dir, "material")}\u3002\u8BF7\u786E\u8BA4 DevEco Studio \u5DF2\u5B89\u88C5\u5E76\u751F\u6210\u8FC7\u7B7E\u540D\u914D\u7F6E\u3002`);
|
|
242
|
+
}
|
|
243
|
+
const key = this.deriveEncryptionKey(dir);
|
|
244
|
+
return {
|
|
245
|
+
keyPassword: this.aesEncrypt(key, password),
|
|
246
|
+
storePassword: this.aesEncrypt(key, password)
|
|
247
|
+
};
|
|
248
|
+
}
|
|
249
|
+
};
|
|
250
|
+
|
|
251
|
+
// src/cli/index.ts
|
|
252
|
+
var program = new Command();
|
|
253
|
+
program.name("agc-cli").description("AppGallery Connect API CLI Tool").version("1.0.0");
|
|
254
|
+
var authCmd = program.command("auth").description("Authentication management");
|
|
255
|
+
authCmd.command("login").description("Login to AGC API and cache the access token").action(async () => {
|
|
256
|
+
try {
|
|
257
|
+
const token = await AuthManager.getAccessToken();
|
|
258
|
+
console.log("Successfully logged in. Token generated and cached.");
|
|
259
|
+
console.log(`Token snippet: ${token.substring(0, 10)}...`);
|
|
260
|
+
} catch (e) {
|
|
261
|
+
console.error("Login failed:", e.message);
|
|
262
|
+
}
|
|
263
|
+
});
|
|
264
|
+
authCmd.command("logout").description("Logout and clear cached access token").action(() => {
|
|
265
|
+
const cleared = AuthManager.clearCache();
|
|
266
|
+
if (cleared) {
|
|
267
|
+
console.log("Successfully logged out. Token cache cleared.");
|
|
268
|
+
} else {
|
|
269
|
+
console.log("Already logged out. No token cache found.");
|
|
270
|
+
}
|
|
271
|
+
});
|
|
272
|
+
var publishCmd = program.command("publish").description("Publishing API commands");
|
|
273
|
+
publishCmd.command("app-id").description("Get App ID by package name").requiredOption("-p, --package-name <packageName>", "Package name").action(async (options) => {
|
|
274
|
+
try {
|
|
275
|
+
const res = await PublishService.getAppIdList(options.packageName);
|
|
276
|
+
console.log(JSON.stringify(res, null, 2));
|
|
277
|
+
} catch (e) {
|
|
278
|
+
console.error("Request failed:", e.message);
|
|
279
|
+
}
|
|
280
|
+
});
|
|
281
|
+
publishCmd.command("app-info").description("Get App Info by App ID").requiredOption("-a, --app-id <appId>", "App ID").option("-l, --lang <lang>", "Language, e.g. zh-CN").action(async (options) => {
|
|
282
|
+
try {
|
|
283
|
+
const res = await PublishService.getAppInfo(options.appId, options.lang);
|
|
284
|
+
console.log(JSON.stringify(res, null, 2));
|
|
285
|
+
} catch (e) {
|
|
286
|
+
console.error("Request failed:", e.message);
|
|
287
|
+
}
|
|
288
|
+
});
|
|
289
|
+
var uploadCmd = program.command("upload").description("Upload Management API commands");
|
|
290
|
+
uploadCmd.command("file").description("Upload a file (APP, APK, images, etc.)").requiredOption("-a, --app-id <appId>", "App ID").requiredOption("-f, --file-path <filePath>", "Path to the local file to upload").option("-r, --release-type <releaseType>", "Release type: 1 for Full, 6 for HarmonyOS Test").option("-c, --chinese-mainland <flag>", "Chinese mainland flag: 0 or 1").action(async (options) => {
|
|
291
|
+
try {
|
|
292
|
+
console.log(`Uploading file ${options.filePath}...`);
|
|
293
|
+
await UploadService.uploadFile({
|
|
294
|
+
appId: options.appId,
|
|
295
|
+
filePath: options.filePath,
|
|
296
|
+
releaseType: options.releaseType ? Number(options.releaseType) : void 0,
|
|
297
|
+
chineseMainlandFlag: options.chineseMainland ? Number(options.chineseMainland) : void 0
|
|
298
|
+
});
|
|
299
|
+
console.log("Upload successful.");
|
|
300
|
+
} catch (e) {
|
|
301
|
+
console.error("Upload failed:", e.message);
|
|
302
|
+
}
|
|
303
|
+
});
|
|
304
|
+
var provisionCmd = program.command("provision").description("Provisioning API commands");
|
|
305
|
+
provisionCmd.command("csr-generate").description("Generate a new keypair and CSR file").requiredOption("--alias <alias>", "Key alias").option("--pwd <pwd>", "Key password (default: 123456)").option("--out-dir <outDir>", "Output directory (default: ./sign_keys)").option("--filename <filename>", "Base filename for generated files").option("--sdk-path <sdkPath>", "Path to HarmonyOS SDK (or set HARMONYOS_SDK_PATH env var)").option("--java-path <javaPath>", "Path to java executable (default: java)").action(async (options) => {
|
|
306
|
+
try {
|
|
307
|
+
const res = await SignService.createSignP12AndCsr({
|
|
308
|
+
alias: options.alias,
|
|
309
|
+
pwd: options.pwd,
|
|
310
|
+
outDir: options.outDir,
|
|
311
|
+
filename: options.filename,
|
|
312
|
+
sdkPath: options.sdkPath,
|
|
313
|
+
javaPath: options.javaPath
|
|
314
|
+
});
|
|
315
|
+
console.log("CSR generation successful.");
|
|
316
|
+
console.log(JSON.stringify(res, null, 2));
|
|
317
|
+
} catch (e) {
|
|
318
|
+
console.error("CSR generation failed:", e.message);
|
|
319
|
+
}
|
|
320
|
+
});
|
|
321
|
+
provisionCmd.command("encrypt-pwd").description("\u52A0\u5BC6 P12 \u5BC6\u7801\uFF0C\u751F\u6210 build-profile.json5 \u6240\u9700\u7684 keyPassword / storePassword").requiredOption("--pwd <password>", "P12 \u5BC6\u7801\u660E\u6587").option("--config-dir <configDir>", "DevEco Studio \u914D\u7F6E\u76EE\u5F55 (\u9ED8\u8BA4 ~/.ohos/config)").action(async (options) => {
|
|
322
|
+
try {
|
|
323
|
+
const res = SignService.encryptPassword(options.pwd, options.configDir);
|
|
324
|
+
console.log(JSON.stringify(res, null, 2));
|
|
325
|
+
} catch (e) {
|
|
326
|
+
console.error("\u52A0\u5BC6\u5931\u8D25:", e.message);
|
|
327
|
+
}
|
|
328
|
+
});
|
|
329
|
+
provisionCmd.command("cert-create").description("Create a certificate").requiredOption("--csr <csrFile>", "Path to CSR file").requiredOption("--cert-name <certName>", "Certificate name").requiredOption("--cert-type <certType>", "Certificate type (1: debug, 2: release, 3: in-house, 4: binary)").action(async (options) => {
|
|
330
|
+
try {
|
|
331
|
+
const csrContent = fs3.readFileSync(options.csr, "utf8");
|
|
332
|
+
const res = await ProvisionService.createCert({
|
|
333
|
+
csr: csrContent,
|
|
334
|
+
certName: options.certName,
|
|
335
|
+
certType: Number(options.certType)
|
|
336
|
+
});
|
|
337
|
+
console.log(JSON.stringify(res, null, 2));
|
|
338
|
+
} catch (e) {
|
|
339
|
+
console.error("Request failed:", e.message);
|
|
340
|
+
}
|
|
341
|
+
});
|
|
342
|
+
provisionCmd.command("cert-list").description("List certificates").option("-t, --cert-type <certType>", "Certificate type").option("--cert-ids <certIds>", "Comma separated certificate IDs").action(async (options) => {
|
|
343
|
+
try {
|
|
344
|
+
const req = {};
|
|
345
|
+
if (options.certType) req.certType = Number(options.certType);
|
|
346
|
+
if (options.certIds) req.certIds = options.certIds.split(",");
|
|
347
|
+
const res = await ProvisionService.getCertList(req);
|
|
348
|
+
console.log(JSON.stringify(res, null, 2));
|
|
349
|
+
} catch (e) {
|
|
350
|
+
console.error("Request failed:", e.message);
|
|
351
|
+
}
|
|
352
|
+
});
|
|
353
|
+
provisionCmd.command("cert-delete").description("Delete certificates").requiredOption("--cert-ids <certIds>", "Comma separated certificate IDs to delete").action(async (options) => {
|
|
354
|
+
try {
|
|
355
|
+
const res = await ProvisionService.deleteCert({
|
|
356
|
+
certIds: options.certIds.split(",")
|
|
357
|
+
});
|
|
358
|
+
console.log(JSON.stringify(res, null, 2));
|
|
359
|
+
} catch (e) {
|
|
360
|
+
console.error("Request failed:", e.message);
|
|
361
|
+
}
|
|
362
|
+
});
|
|
363
|
+
provisionCmd.command("device-add").description("Add new devices").requiredOption("--devices <devicesFile>", 'Path to JSON file containing devices array [{"deviceName":"name","udid":"udid","deviceType":1}]').action(async (options) => {
|
|
364
|
+
try {
|
|
365
|
+
const fileContent = fs3.readFileSync(options.devices, "utf8");
|
|
366
|
+
const deviceList = JSON.parse(fileContent);
|
|
367
|
+
const res = await ProvisionService.addDevice({ deviceList });
|
|
368
|
+
console.log(JSON.stringify(res, null, 2));
|
|
369
|
+
} catch (e) {
|
|
370
|
+
console.error("Request failed:", e.message);
|
|
371
|
+
}
|
|
372
|
+
});
|
|
373
|
+
provisionCmd.command("device-list").description("List devices").option("--device-name <deviceName>", "Device name to search").option("--from <fromRecCount>", "Starting page").option("--max <maxReqCount>", "Max items per page").option("--order <order>", "1: create time desc, 2: name asc").action(async (options) => {
|
|
374
|
+
try {
|
|
375
|
+
const req = {};
|
|
376
|
+
if (options.deviceName) req.deviceName = options.deviceName;
|
|
377
|
+
if (options.from) req.fromRecCount = Number(options.from);
|
|
378
|
+
if (options.max) req.maxReqCount = Number(options.max);
|
|
379
|
+
if (options.order) req.order = Number(options.order);
|
|
380
|
+
const res = await ProvisionService.getDeviceList(req);
|
|
381
|
+
console.log(JSON.stringify(res, null, 2));
|
|
382
|
+
} catch (e) {
|
|
383
|
+
console.error("Request failed:", e.message);
|
|
384
|
+
}
|
|
385
|
+
});
|
|
386
|
+
provisionCmd.command("device-delete").description("Delete devices").requiredOption("--device-ids <deviceIdList>", "Comma separated device IDs to delete").action(async (options) => {
|
|
387
|
+
try {
|
|
388
|
+
const res = await ProvisionService.deleteDevice({
|
|
389
|
+
deviceIdList: options.deviceIds.split(",")
|
|
390
|
+
});
|
|
391
|
+
console.log(JSON.stringify(res, null, 2));
|
|
392
|
+
} catch (e) {
|
|
393
|
+
console.error("Request failed:", e.message);
|
|
394
|
+
}
|
|
395
|
+
});
|
|
396
|
+
provisionCmd.command("profile-create").description("Create a profile").requiredOption("--name <provisionName>", "Profile name").requiredOption("--type <provisionType>", "Profile type (1:debug, 2:release, 3:in-house, 6:specific device)").requiredOption("--cert <certId>", "Certificate ID").requiredOption("-a, --app-id <appId>", "App ID").option("--device-ids <deviceIdList>", "Comma separated device IDs").option("--acls <aclPermissionList>", "Comma separated ACL permissions").action(async (options) => {
|
|
397
|
+
try {
|
|
398
|
+
const req = {
|
|
399
|
+
provisionName: options.name,
|
|
400
|
+
provisionType: Number(options.type),
|
|
401
|
+
certId: options.cert,
|
|
402
|
+
appId: options.appId
|
|
403
|
+
};
|
|
404
|
+
if (options.deviceIds) req.deviceIdList = options.deviceIds.split(",");
|
|
405
|
+
if (options.acls) req.aclPermissionList = options.acls.split(",");
|
|
406
|
+
const res = await ProvisionService.createProvision(req);
|
|
407
|
+
console.log(JSON.stringify(res, null, 2));
|
|
408
|
+
} catch (e) {
|
|
409
|
+
console.error("Request failed:", e.message);
|
|
410
|
+
}
|
|
411
|
+
});
|
|
412
|
+
provisionCmd.command("profile-list").description("List profiles").requiredOption("-a, --app-id <appId>", "App ID").option("--profile-id <provisionId>", "Profile ID").option("--from <fromRecCount>", "Starting page").option("--max <maxReqCount>", "Max items per page").action(async (options) => {
|
|
413
|
+
try {
|
|
414
|
+
const req = { appId: options.appId };
|
|
415
|
+
if (options.profileId) req.provisionId = options.profileId;
|
|
416
|
+
if (options.from) req.fromRecCount = Number(options.from);
|
|
417
|
+
if (options.max) req.maxReqCount = Number(options.max);
|
|
418
|
+
const res = await ProvisionService.getProvisionList(req);
|
|
419
|
+
console.log(JSON.stringify(res, null, 2));
|
|
420
|
+
} catch (e) {
|
|
421
|
+
console.error("Request failed:", e.message);
|
|
422
|
+
}
|
|
423
|
+
});
|
|
424
|
+
provisionCmd.command("profile-update").description("Update profile devices").requiredOption("--id <provisionId>", "Profile ID").requiredOption("--device-ids <deviceIdList>", "Comma separated device IDs").action(async (options) => {
|
|
425
|
+
try {
|
|
426
|
+
const res = await ProvisionService.updateProvision({
|
|
427
|
+
provisionId: options.id,
|
|
428
|
+
deviceIdList: options.deviceIds.split(",")
|
|
429
|
+
});
|
|
430
|
+
console.log(JSON.stringify(res, null, 2));
|
|
431
|
+
} catch (e) {
|
|
432
|
+
console.error("Request failed:", e.message);
|
|
433
|
+
}
|
|
434
|
+
});
|
|
435
|
+
provisionCmd.command("profile-delete").description("Delete a profile").requiredOption("--id <id>", "Profile ID to delete").action(async (options) => {
|
|
436
|
+
try {
|
|
437
|
+
const res = await ProvisionService.deleteProvision({ id: options.id });
|
|
438
|
+
console.log(JSON.stringify(res, null, 2));
|
|
439
|
+
} catch (e) {
|
|
440
|
+
console.error("Request failed:", e.message);
|
|
441
|
+
}
|
|
442
|
+
});
|
|
443
|
+
provisionCmd.command("fp-add").description("Add certificate fingerprints").requiredOption("-a, --app-id <appId>", "App ID").requiredOption("--fps <fingerprintList>", "Comma separated fingerprints").action(async (options) => {
|
|
444
|
+
try {
|
|
445
|
+
const res = await ProvisionService.addFingerprint({
|
|
446
|
+
appId: options.appId,
|
|
447
|
+
fingerprintList: options.fps.split(",")
|
|
448
|
+
});
|
|
449
|
+
console.log(JSON.stringify(res, null, 2));
|
|
450
|
+
} catch (e) {
|
|
451
|
+
console.error("Request failed:", e.message);
|
|
452
|
+
}
|
|
453
|
+
});
|
|
454
|
+
provisionCmd.command("fp-list").description("List certificate fingerprints").requiredOption("-a, --app-id <appId>", "App ID").action(async (options) => {
|
|
455
|
+
try {
|
|
456
|
+
const res = await ProvisionService.getFingerprintList({ appId: options.appId });
|
|
457
|
+
console.log(JSON.stringify(res, null, 2));
|
|
458
|
+
} catch (e) {
|
|
459
|
+
console.error("Request failed:", e.message);
|
|
460
|
+
}
|
|
461
|
+
});
|
|
462
|
+
provisionCmd.command("fp-delete").description("Delete certificate fingerprints").requiredOption("-a, --app-id <appId>", "App ID").requiredOption("--fps <fingerprintList>", "Comma separated fingerprints to delete").action(async (options) => {
|
|
463
|
+
try {
|
|
464
|
+
const res = await ProvisionService.deleteFingerprint({
|
|
465
|
+
appId: options.appId,
|
|
466
|
+
fingerprintList: options.fps.split(",")
|
|
467
|
+
});
|
|
468
|
+
console.log(JSON.stringify(res, null, 2));
|
|
469
|
+
} catch (e) {
|
|
470
|
+
console.error("Request failed:", e.message);
|
|
471
|
+
}
|
|
472
|
+
});
|
|
473
|
+
provisionCmd.command("acl-apply").description("Apply for restricted ACL permissions").requiredOption("-a, --app-id <appId>", "App ID").requiredOption("--acls <aclsFile>", 'Path to JSON file containing ACL permissions [{"name":"name","reason":"reason"}]').option("--attachment <attachment>", "Attachment object ID").action(async (options) => {
|
|
474
|
+
try {
|
|
475
|
+
const fileContent = fs3.readFileSync(options.acls, "utf8");
|
|
476
|
+
const aclPermissionList = JSON.parse(fileContent);
|
|
477
|
+
const req = { appId: options.appId, aclPermissionList };
|
|
478
|
+
if (options.attachment) req.attachment = options.attachment;
|
|
479
|
+
const res = await ProvisionService.applyACL(req);
|
|
480
|
+
console.log(JSON.stringify(res, null, 2));
|
|
481
|
+
} catch (e) {
|
|
482
|
+
console.error("Request failed:", e.message);
|
|
483
|
+
}
|
|
484
|
+
});
|
|
485
|
+
provisionCmd.command("acl-status").description("Check ACL permission apply status").requiredOption("-a, --app-id <appId>", "App ID").action(async (options) => {
|
|
486
|
+
try {
|
|
487
|
+
const res = await ProvisionService.getACLStatus({ appId: options.appId });
|
|
488
|
+
console.log(JSON.stringify(res, null, 2));
|
|
489
|
+
} catch (e) {
|
|
490
|
+
console.error("Request failed:", e.message);
|
|
491
|
+
}
|
|
492
|
+
});
|
|
493
|
+
provisionCmd.command("acl-query").description("Query granted ACL permissions").requiredOption("-a, --app-id <appId>", "App ID").action(async (options) => {
|
|
494
|
+
try {
|
|
495
|
+
const res = await ProvisionService.getACLQuery({ appId: options.appId });
|
|
496
|
+
console.log(JSON.stringify(res, null, 2));
|
|
497
|
+
} catch (e) {
|
|
498
|
+
console.error("Request failed:", e.message);
|
|
499
|
+
}
|
|
500
|
+
});
|
|
501
|
+
var domainCmd = program.command("domain").description("Domain Management API commands");
|
|
502
|
+
domainCmd.command("query").description("Query domain configuration").requiredOption("-a, --app-id <appId>", "App ID").requiredOption("-c, --category <category>", "Category: server or business").action(async (options) => {
|
|
503
|
+
try {
|
|
504
|
+
const res = await DomainService.queryDomain({
|
|
505
|
+
appId: options.appId,
|
|
506
|
+
category: options.category
|
|
507
|
+
});
|
|
508
|
+
console.log(JSON.stringify(res, null, 2));
|
|
509
|
+
} catch (e) {
|
|
510
|
+
console.error("Request failed:", e.message);
|
|
511
|
+
}
|
|
512
|
+
});
|
|
513
|
+
domainCmd.command("update").description("Add or update domain configuration").requiredOption("-a, --app-id <appId>", "App ID").requiredOption("-c, --category <category>", "Category: server or business").requiredOption("--domains <domainsFile>", 'Path to JSON file containing domains array [{"type":"httpRequest","value":"https://..."}]').action(async (options) => {
|
|
514
|
+
try {
|
|
515
|
+
const fileContent = fs3.readFileSync(options.domains, "utf8");
|
|
516
|
+
const domains = JSON.parse(fileContent);
|
|
517
|
+
const res = await DomainService.updateDomain({
|
|
518
|
+
appId: options.appId,
|
|
519
|
+
category: options.category,
|
|
520
|
+
domains
|
|
521
|
+
});
|
|
522
|
+
console.log(JSON.stringify(res, null, 2));
|
|
523
|
+
} catch (e) {
|
|
524
|
+
console.error("Request failed:", e.message);
|
|
525
|
+
}
|
|
526
|
+
});
|
|
527
|
+
domainCmd.command("config").description("Query domain modification counts and limits").requiredOption("-a, --app-id <appId>", "App ID").action(async (options) => {
|
|
528
|
+
try {
|
|
529
|
+
const res = await DomainService.queryDomainConfig({
|
|
530
|
+
appId: options.appId
|
|
531
|
+
});
|
|
532
|
+
console.log(JSON.stringify(res, null, 2));
|
|
533
|
+
} catch (e) {
|
|
534
|
+
console.error("Request failed:", e.message);
|
|
535
|
+
}
|
|
536
|
+
});
|
|
537
|
+
domainCmd.command("verify-file").description("Download domain verify file").requiredOption("-a, --app-id <appId>", "App ID").requiredOption("-o, --output <outputPath>", "Output file path").action(async (options) => {
|
|
538
|
+
try {
|
|
539
|
+
console.log(`Downloading verify file to ${options.output}...`);
|
|
540
|
+
await DomainService.verifyFile({
|
|
541
|
+
appId: options.appId
|
|
542
|
+
}, options.output);
|
|
543
|
+
console.log("Download successful.");
|
|
544
|
+
} catch (e) {
|
|
545
|
+
console.error("Download failed:", e.message);
|
|
546
|
+
}
|
|
547
|
+
});
|
|
548
|
+
domainCmd.command("pre-check").description("Pre-check business domain configuration").requiredOption("-a, --app-id <appId>", "App ID").requiredOption("--domain <domainFile>", 'Path to JSON file containing domain object {"type":"webView","value":"https://..."}').action(async (options) => {
|
|
549
|
+
try {
|
|
550
|
+
const fileContent = fs3.readFileSync(options.domain, "utf8");
|
|
551
|
+
const domain = JSON.parse(fileContent);
|
|
552
|
+
const res = await DomainService.preCheckDomain({
|
|
553
|
+
appId: options.appId,
|
|
554
|
+
domain
|
|
555
|
+
});
|
|
556
|
+
console.log(JSON.stringify(res, null, 2));
|
|
557
|
+
} catch (e) {
|
|
558
|
+
console.error("Request failed:", e.message);
|
|
559
|
+
}
|
|
560
|
+
});
|
|
561
|
+
program.parse(process.argv);
|
|
562
|
+
//# sourceMappingURL=cli.mjs.map
|