cloudcc-cli 2.3.4 → 2.3.5
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/.claude/settings.json +22 -1
- package/.cursor/skills/cloudcc-cli-dev/SKILL.md +175 -0
- package/.cursor/skills/cloudcc-dev-skill/SKILL.md +71 -0
- package/README.md +54 -7
- package/bin/cc.js +106 -28
- package/bin/index.js +54 -55
- package/mcp/cliRunner.js +11 -4
- package/mcp/index.js +12 -2
- package/mcp/tools/CloudCC Development Overview/handler.js +1 -1
- package/mcp/tools/JSP Migrator/handler.js +46 -0
- package/package.json +3 -4
- package/src/button/create.js +169 -0
- package/src/button/delete.js +35 -0
- package/src/button/doc.js +36 -0
- package/src/button/docs/devguide.md +133 -0
- package/src/button/docs/introduction.md +60 -0
- package/src/button/get.js +60 -0
- package/src/button/index.js +20 -0
- package/src/classes/docs/introduction.md +0 -20
- package/src/identityProvider/create.js +78 -0
- package/src/identityProvider/delete.js +61 -0
- package/src/identityProvider/doc.js +46 -0
- package/src/identityProvider/docs/devguide.md +107 -0
- package/src/identityProvider/docs/introduction.md +31 -0
- package/src/identityProvider/download.js +105 -0
- package/src/identityProvider/get.js +70 -0
- package/src/identityProvider/index.js +12 -0
- package/src/permission/add.js +164 -0
- package/src/permission/assign.js +84 -0
- package/src/permission/docs/devguide.md +238 -0
- package/src/permission/docs/introduction.md +200 -0
- package/src/permission/get.js +107 -0
- package/src/permission/index.js +10 -0
- package/src/permission/remove.js +145 -0
- package/src/project/docs/devguide.md +7 -6
- package/src/singleSignOn/delete.js +61 -0
- package/src/singleSignOn/doc.js +46 -0
- package/src/singleSignOn/docs/devguide.md +61 -0
- package/src/singleSignOn/docs/introduction.md +3 -0
- package/src/singleSignOn/get.js +70 -0
- package/src/singleSignOn/index.js +10 -0
- package/src/staticResource/docs/introduction.md +44 -1
- package/src/validationRule/create.js +2 -2
- package/src/version/actionHelp.js +25 -0
- package/src/version/docs.js +26 -0
- package/src/version/doctor.js +25 -0
- package/src/version/get.js +7 -1
- package/src/version/help.js +47 -0
- package/src/version/index.js +9 -2
- package/src/version/initHelp.js +13 -0
- package/src/version/listModuleCommands.js +241 -0
- package/src/version/stats.js +44 -0
- package/src/version/uninstall.js +30 -0
- package/src/version/update.js +13 -0
- package/utils/checkVersion.js +31 -2
- package/utils/commandStats.js +94 -0
- package/utils/formatReleaseNotes.js +312 -0
- package/utils/readmeReleases.js +69 -0
- package/.cloudcc-cache.json +0 -54
- package/.cursor/skills/cloudcc-cli-dev.zip +0 -0
- package/.cursor/skills/cloudcc-dev-usage/SKILL.md +0 -68
- package/build/component-cc-cc-dd.common.js +0 -831
- package/build/component-cc-cc-dd.common.js.map +0 -1
- package/build/component-cc-cc-dd.css +0 -1
- package/build/component-cc-cc-dd.umd.js +0 -874
- package/build/component-cc-cc-dd.umd.js.map +0 -1
- package/build/component-cc-cc-dd.umd.min.js +0 -8
- package/build/component-cc-cc-dd.umd.min.js.map +0 -1
- package/build/demo.html +0 -1
- package/plugins/cc-cc-dd/cc-cc-dd.vue +0 -32
- package/plugins/cc-cc-dd/components/HelloWorld.vue +0 -11
- package/plugins/cc-cc-dd/config.json +0 -6
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
const chalk = require("chalk");
|
|
2
|
+
const { postClass } = require("../../utils/http");
|
|
3
|
+
const { getPackageJson } = require("../../utils/config");
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* 创建身份提供商
|
|
7
|
+
* 接口: /samlSp/save
|
|
8
|
+
* 用法:cc create identityProvider <path> <entityid> <acsurl>
|
|
9
|
+
*/
|
|
10
|
+
async function create(argvs) {
|
|
11
|
+
try {
|
|
12
|
+
const projectPath = argvs[2] || process.cwd();
|
|
13
|
+
const entityid = argvs[3];
|
|
14
|
+
const acsurl = argvs[4];
|
|
15
|
+
|
|
16
|
+
if (!entityid || !acsurl) {
|
|
17
|
+
console.error();
|
|
18
|
+
console.error(chalk.red("Error: 缺少必需参数"));
|
|
19
|
+
console.error(chalk.yellow("用法: cc create identityProvider <path> <entityid> <acsurl>"));
|
|
20
|
+
console.error(chalk.yellow("示例: cc create identityProvider . 'http://testdev.cloudcc.cn/ccdomaingateway/apisvc' 'http://testdev.cloudcc.cn/ccdomaingateway/apisvc/saml2/sp/sso/acs'"));
|
|
21
|
+
console.error();
|
|
22
|
+
throw new Error("缺少必需参数: entityid 和 acsurl");
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
const config = await getPackageJson(projectPath);
|
|
26
|
+
if (!config || !config.accessToken) {
|
|
27
|
+
console.error();
|
|
28
|
+
console.error(chalk.red("Error: 配置未找到或 accessToken 缺失"));
|
|
29
|
+
console.error();
|
|
30
|
+
throw new Error("配置未找到或 accessToken 缺失");
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
console.error();
|
|
34
|
+
console.error(chalk.green(`Creating identity provider, please wait...`));
|
|
35
|
+
console.error();
|
|
36
|
+
|
|
37
|
+
// 构建请求参数
|
|
38
|
+
const body = {
|
|
39
|
+
entityid: entityid,
|
|
40
|
+
acsurl: acsurl,
|
|
41
|
+
issuername: "",
|
|
42
|
+
nameidtype: "FederationId",
|
|
43
|
+
nameidformat: "1",
|
|
44
|
+
enablelogout: false,
|
|
45
|
+
logouturl: "",
|
|
46
|
+
custattrname: "",
|
|
47
|
+
id: ""
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
const res = await postClass(
|
|
51
|
+
config.setupSvc + "/api/samlSp/save",
|
|
52
|
+
body,
|
|
53
|
+
config.accessToken
|
|
54
|
+
);
|
|
55
|
+
|
|
56
|
+
if (res && res.result) {
|
|
57
|
+
console.error();
|
|
58
|
+
console.error(chalk.green("Success! Identity provider created."));
|
|
59
|
+
if (res.data) {
|
|
60
|
+
console.error(chalk.gray(`Response: ${JSON.stringify(res.data, null, 2)}`));
|
|
61
|
+
}
|
|
62
|
+
console.error();
|
|
63
|
+
return res;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
const msg = res && (res.returnInfo || res.message) ? (res.returnInfo || res.message) : "Unknown error";
|
|
67
|
+
console.error();
|
|
68
|
+
console.error(chalk.red("Error: " + msg));
|
|
69
|
+
console.error();
|
|
70
|
+
throw new Error("Create IdentityProvider Failed: " + msg);
|
|
71
|
+
} catch (error) {
|
|
72
|
+
console.error();
|
|
73
|
+
console.error(chalk.red("身份提供商创建失败:"), error.message || error);
|
|
74
|
+
throw error;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
module.exports = create;
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
const chalk = require("chalk");
|
|
2
|
+
const { postClass } = require("../../utils/http");
|
|
3
|
+
const { getPackageJson } = require("../../utils/config");
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* 删除身份提供商
|
|
7
|
+
* 接口: /samlSp/delete
|
|
8
|
+
* 用法:cc delete identityProvider <projectPath> <appId>
|
|
9
|
+
*/
|
|
10
|
+
async function remove(argvs) {
|
|
11
|
+
try {
|
|
12
|
+
const projectPath = argvs[2] || process.cwd();
|
|
13
|
+
const appId = argvs[3];
|
|
14
|
+
|
|
15
|
+
if (!appId) {
|
|
16
|
+
console.error();
|
|
17
|
+
console.error(chalk.red("Error: 缺少身份提供商 app ID"));
|
|
18
|
+
console.error(chalk.yellow("用法: cc delete identityProvider <projectPath> <appId>"));
|
|
19
|
+
console.error(chalk.yellow("示例: cc delete identityProvider . QbjH30d9Oy"));
|
|
20
|
+
console.error();
|
|
21
|
+
throw new Error("缺少必需参数: appId");
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const config = await getPackageJson(projectPath);
|
|
25
|
+
if (!config || !config.accessToken) {
|
|
26
|
+
console.error();
|
|
27
|
+
console.error(chalk.red("Error: 配置未找到或 accessToken 缺失"));
|
|
28
|
+
console.error();
|
|
29
|
+
throw new Error("配置未找到或 accessToken 缺失");
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
console.error();
|
|
33
|
+
console.error(chalk.green(`Deleting identity provider (${appId}), please wait...`));
|
|
34
|
+
console.error();
|
|
35
|
+
|
|
36
|
+
const result = await postClass(
|
|
37
|
+
config.setupSvc + "/api/samlSp/delete",
|
|
38
|
+
{ app: appId },
|
|
39
|
+
config.accessToken
|
|
40
|
+
);
|
|
41
|
+
|
|
42
|
+
if (result && result.result) {
|
|
43
|
+
console.error();
|
|
44
|
+
console.error(chalk.green("Success! Identity provider deleted."));
|
|
45
|
+
console.error();
|
|
46
|
+
return result;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
const msg = result && (result.returnInfo || result.message) ? (result.returnInfo || result.message) : "Unknown error";
|
|
50
|
+
console.error();
|
|
51
|
+
console.error(chalk.red("Error: " + msg));
|
|
52
|
+
console.error();
|
|
53
|
+
throw new Error("Delete IdentityProvider Failed: " + msg);
|
|
54
|
+
} catch (error) {
|
|
55
|
+
console.error();
|
|
56
|
+
console.error(chalk.red("身份提供商删除失败:"), error);
|
|
57
|
+
throw error;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
module.exports = remove;
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* identityProvider 文档入口:正文均在 `docs/` 目录。
|
|
3
|
+
*/
|
|
4
|
+
const fs = require("fs");
|
|
5
|
+
const path = require("path");
|
|
6
|
+
|
|
7
|
+
const DOCS_DIR = path.join(__dirname, "docs");
|
|
8
|
+
|
|
9
|
+
function readDocFile(basename) {
|
|
10
|
+
return fs.readFileSync(path.join(DOCS_DIR, `${basename}.md`), "utf8");
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
/** 介绍文档:身份提供商能力、类型与入口 */
|
|
14
|
+
function getIntroductionDoc() {
|
|
15
|
+
return readDocFile("introduction");
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/** 开发指导:CLI 创建/查询/删除等 */
|
|
19
|
+
function getDevGuideDoc() {
|
|
20
|
+
return readDocFile("devguide");
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* cc doc identityProvider <introduction|devguide>
|
|
25
|
+
* @param {string[]} argvs [doc, type, introduction|devguide, ...]
|
|
26
|
+
*/
|
|
27
|
+
function doc(argvs) {
|
|
28
|
+
const subType = argvs[2];
|
|
29
|
+
const key = String(subType || "").trim().toLowerCase();
|
|
30
|
+
if (!key) {
|
|
31
|
+
throw new Error("cc doc identityProvider 需要子命令:introduction 或 devguide");
|
|
32
|
+
}
|
|
33
|
+
if (key === "introduction") {
|
|
34
|
+
const content = getIntroductionDoc();
|
|
35
|
+
console.log(content);
|
|
36
|
+
return content;
|
|
37
|
+
}
|
|
38
|
+
if (key === "devguide") {
|
|
39
|
+
const content = getDevGuideDoc();
|
|
40
|
+
console.log(content);
|
|
41
|
+
return content;
|
|
42
|
+
}
|
|
43
|
+
throw new Error(`doc 不支持的子命令: ${subType},请使用 introduction 或 devguide`);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
module.exports = doc;
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
# CloudCC 身份提供商 CLI 命令说明
|
|
2
|
+
|
|
3
|
+
## 支持的命令
|
|
4
|
+
|
|
5
|
+
| 操作 | 说明 |
|
|
6
|
+
|------|------|
|
|
7
|
+
| `create` | 创建新身份提供商 |
|
|
8
|
+
| `get` | 查询身份提供商列表 |
|
|
9
|
+
| `delete` | 删除身份提供商 |
|
|
10
|
+
| `download` | 下载身份提供商证书 |
|
|
11
|
+
|
|
12
|
+
## CLI 命令详解
|
|
13
|
+
|
|
14
|
+
### 创建身份提供商
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
cc create identityProvider <path> <entityid> <acsurl>
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
**参数说明:**
|
|
21
|
+
|
|
22
|
+
| 参数 | 必填 | 说明 |
|
|
23
|
+
|------|------|------|
|
|
24
|
+
| `path` | 是 | 项目路径,`.` 表示当前目录 |
|
|
25
|
+
| `entityid` | 是 | 实体 ID(Service Provider Entity ID)|
|
|
26
|
+
| `acsurl` | 是 | ACS URL(Assertion Consumer Service URL)|
|
|
27
|
+
|
|
28
|
+
**示例:**
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
# 创建身份提供商
|
|
32
|
+
cc create identityProvider . "http://testdev.cloudcc.cn/ccdomaingateway/apisvc" "http://testdev.cloudcc.cn/ccdomaingateway/apisvc/saml2/sp/sso/acs"
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
### 查询身份提供商列表
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
cc get identityProvider <projectPath> [encodedCondJson]
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
**参数说明:**
|
|
42
|
+
|
|
43
|
+
| 参数 | 必填 | 说明 |
|
|
44
|
+
|------|------|------|
|
|
45
|
+
| `projectPath` | 否 | 项目路径,默认当前目录 |
|
|
46
|
+
| `encodedCondJson` | 否 | URI 编码后的查询条件 JSON |
|
|
47
|
+
|
|
48
|
+
**查询条件参数:**
|
|
49
|
+
|
|
50
|
+
| 参数名 | 类型 | 说明 |
|
|
51
|
+
|--------|------|------|
|
|
52
|
+
| `start` | number | 起始位置,默认 0 |
|
|
53
|
+
| `limit` | number | 每页条数,默认 30 |
|
|
54
|
+
| `keyword` | string | 搜索关键词 |
|
|
55
|
+
|
|
56
|
+
**示例:**
|
|
57
|
+
|
|
58
|
+
```bash
|
|
59
|
+
# 获取所有身份提供商
|
|
60
|
+
cc get identityProvider .
|
|
61
|
+
|
|
62
|
+
# 带查询条件(搜索关键词)
|
|
63
|
+
cc get identityProvider . '%7B%22keyword%22%3A%22test%22%2C%22limit%22%3A50%7D'
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
### 删除身份提供商
|
|
67
|
+
|
|
68
|
+
```bash
|
|
69
|
+
cc delete identityProvider <projectPath> <appId>
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
**参数说明:**
|
|
73
|
+
|
|
74
|
+
| 参数 | 必填 | 说明 |
|
|
75
|
+
|------|------|------|
|
|
76
|
+
| `projectPath` | 否 | 项目路径,默认当前目录 |
|
|
77
|
+
| `appId` | 是 | 身份提供商的 app 字段值(从列表接口获取)|
|
|
78
|
+
|
|
79
|
+
**示例:**
|
|
80
|
+
|
|
81
|
+
```bash
|
|
82
|
+
# 删除身份提供商
|
|
83
|
+
cc delete identityProvider . QbjH30d9Oy
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
### 下载身份提供商证书
|
|
87
|
+
|
|
88
|
+
```bash
|
|
89
|
+
cc download identityProvider <projectPath> [savePath]
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
**参数说明:**
|
|
93
|
+
|
|
94
|
+
| 参数 | 必填 | 说明 |
|
|
95
|
+
|------|------|------|
|
|
96
|
+
| `projectPath` | 否 | 项目路径,默认当前目录 |
|
|
97
|
+
| `savePath` | 否 | 证书保存路径,默认当前目录 |
|
|
98
|
+
|
|
99
|
+
**示例:**
|
|
100
|
+
|
|
101
|
+
```bash
|
|
102
|
+
# 下载证书到当前目录
|
|
103
|
+
cc download identityProvider .
|
|
104
|
+
|
|
105
|
+
# 下载证书到指定路径
|
|
106
|
+
cc download identityProvider . ./certificates
|
|
107
|
+
```
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# 身份提供商介绍
|
|
2
|
+
|
|
3
|
+
## 功能概述
|
|
4
|
+
|
|
5
|
+
身份提供商(Identity Provider)模块用于管理 CloudCC 平台的 SAML 身份提供商配置,支持以下功能:
|
|
6
|
+
|
|
7
|
+
- **查看身份提供商列表**:查询已配置的所有 SAML 身份提供商
|
|
8
|
+
- **新建身份提供商**:创建新的 SAML 身份提供商配置
|
|
9
|
+
- **删除身份提供商**:删除已配置的 SAML 身份提供商
|
|
10
|
+
- **下载证书**:下载身份提供商的 SAML 证书
|
|
11
|
+
|
|
12
|
+
## 适用场景
|
|
13
|
+
|
|
14
|
+
- 企业单点登录(SSO)集成
|
|
15
|
+
- SAML 2.0 身份提供商配置
|
|
16
|
+
- 多身份提供商管理
|
|
17
|
+
|
|
18
|
+
## 字段说明
|
|
19
|
+
|
|
20
|
+
### 身份提供商字段
|
|
21
|
+
|
|
22
|
+
| 字段名 | 说明 | 默认值 |
|
|
23
|
+
|--------|------|--------|
|
|
24
|
+
| `entityid` | Service Provider Entity ID | 用户输入 |
|
|
25
|
+
| `acsurl` | Assertion Consumer Service URL | 用户输入 |
|
|
26
|
+
| `issuername` | 签发者名称 | 空字符串 |
|
|
27
|
+
| `nameidtype` | Name ID 类型 | FederationId |
|
|
28
|
+
| `nameidformat` | Name ID 格式 | 1 |
|
|
29
|
+
| `enablelogout` | 启用注销 | false |
|
|
30
|
+
| `logouturl` | 注销 URL | 空字符串 |
|
|
31
|
+
| `custattrname` | 自定义属性名称 | 空字符串 |
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
const chalk = require("chalk");
|
|
2
|
+
const fs = require("fs");
|
|
3
|
+
const path = require("path");
|
|
4
|
+
const axios = require("axios");
|
|
5
|
+
const https = require("https");
|
|
6
|
+
const { getPackageJson } = require("../../utils/config");
|
|
7
|
+
const { postClass } = require("../../utils/http");
|
|
8
|
+
|
|
9
|
+
const httpsAgent = new https.Agent({
|
|
10
|
+
rejectUnauthorized: false,
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* 下载身份提供商证书
|
|
15
|
+
* 接口: /LoginHistory/getExportReportURL 获取下载链接,然后下载文件
|
|
16
|
+
* 用法:cc download identityProvider <projectPath> [savePath]
|
|
17
|
+
*/
|
|
18
|
+
async function download(argvs) {
|
|
19
|
+
try {
|
|
20
|
+
const projectPath = argvs[2] || process.cwd();
|
|
21
|
+
const savePath = argvs[3] || process.cwd();
|
|
22
|
+
|
|
23
|
+
const config = await getPackageJson(projectPath);
|
|
24
|
+
if (!config || !config.accessToken) {
|
|
25
|
+
console.error();
|
|
26
|
+
console.error(chalk.red("Error: 配置未找到或 accessToken 缺失"));
|
|
27
|
+
console.error();
|
|
28
|
+
throw new Error("配置未找到或 accessToken 缺失");
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
console.error();
|
|
32
|
+
console.error(chalk.green("Downloading certificate, please wait..."));
|
|
33
|
+
console.error();
|
|
34
|
+
|
|
35
|
+
// 确保证书保存目录存在
|
|
36
|
+
if (!fs.existsSync(savePath)) {
|
|
37
|
+
fs.mkdirSync(savePath, { recursive: true });
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
// 第一步:调用接口获取下载 URL
|
|
41
|
+
const result = await postClass(
|
|
42
|
+
config.setupSvc + "/api/LoginHistory/getExportReportURL",
|
|
43
|
+
{},
|
|
44
|
+
config.accessToken
|
|
45
|
+
);
|
|
46
|
+
|
|
47
|
+
if (result && result.result && result.data) {
|
|
48
|
+
const downloadUrl = result.data;
|
|
49
|
+
|
|
50
|
+
console.error(chalk.gray(`Got download URL: ${downloadUrl}`));
|
|
51
|
+
console.error(chalk.gray(`Downloading file...`));
|
|
52
|
+
console.error();
|
|
53
|
+
|
|
54
|
+
// 第二步:根据返回的 URL 下载文件
|
|
55
|
+
const response = await axios({
|
|
56
|
+
method: 'get',
|
|
57
|
+
url: downloadUrl,
|
|
58
|
+
httpsAgent: httpsAgent,
|
|
59
|
+
responseType: 'arraybuffer',
|
|
60
|
+
timeout: 120000
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
// 尝试从响应头获取文件名
|
|
64
|
+
let filename = "identity-provider.crt";
|
|
65
|
+
const contentDisposition = response.headers['content-disposition'];
|
|
66
|
+
if (contentDisposition) {
|
|
67
|
+
const match = contentDisposition.match(/filename[^;=\n]*=((['"]).*?\2|[^;\n]*)/);
|
|
68
|
+
if (match && match[1]) {
|
|
69
|
+
filename = match[1].replace(/['"]/g, '');
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// 如果 URL 中包含文件名,也尝试从中提取
|
|
74
|
+
const urlPath = new URL(downloadUrl).pathname;
|
|
75
|
+
const urlFilename = urlPath.split('/').pop();
|
|
76
|
+
if (urlFilename && urlFilename.includes('.')) {
|
|
77
|
+
filename = urlFilename;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
const filePath = path.join(savePath, filename);
|
|
81
|
+
fs.writeFileSync(filePath, response.data);
|
|
82
|
+
|
|
83
|
+
console.error();
|
|
84
|
+
console.error(chalk.green("Success! Certificate downloaded."));
|
|
85
|
+
console.error(chalk.gray(`Saved to: ${filePath}`));
|
|
86
|
+
console.error();
|
|
87
|
+
|
|
88
|
+
return {
|
|
89
|
+
result: true,
|
|
90
|
+
filePath: filePath,
|
|
91
|
+
filename: filename,
|
|
92
|
+
downloadUrl: downloadUrl
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
const msg = result && (result.returnInfo || result.message) ? (result.returnInfo || result.message) : "Unknown error";
|
|
97
|
+
throw new Error("Get download URL failed: " + msg);
|
|
98
|
+
} catch (error) {
|
|
99
|
+
console.error();
|
|
100
|
+
console.error(chalk.red("证书下载失败:"), error.message || error);
|
|
101
|
+
throw error;
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
module.exports = download;
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
const { postClass } = require("../../utils/http");
|
|
2
|
+
const { getPackageJson } = require("../../utils/config");
|
|
3
|
+
const chalk = require("chalk");
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* 查询身份提供商列表
|
|
7
|
+
* 接口: /samlSp/queryList
|
|
8
|
+
* 用法:cc get identityProvider <projectPath> [encodedCondJson]
|
|
9
|
+
*/
|
|
10
|
+
async function get(argvs, isMcp = false) {
|
|
11
|
+
const projectPath = argvs[2] || process.cwd();
|
|
12
|
+
const condArg = argvs[3];
|
|
13
|
+
|
|
14
|
+
let body = {};
|
|
15
|
+
if (condArg) {
|
|
16
|
+
try {
|
|
17
|
+
body = JSON.parse(decodeURI(condArg));
|
|
18
|
+
} catch (e) {
|
|
19
|
+
try {
|
|
20
|
+
body = JSON.parse(condArg);
|
|
21
|
+
} catch (e2) {
|
|
22
|
+
throw new Error("Get IdentityProvider Failed: encodedCondJson 解析失败,请传 encodeURI(JSON.stringify(...))");
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
const config = await getPackageJson(projectPath);
|
|
28
|
+
|
|
29
|
+
const res = await postClass(
|
|
30
|
+
config.setupSvc + "/api/samlSp/queryList",
|
|
31
|
+
{
|
|
32
|
+
start: 0,
|
|
33
|
+
limit: 30,
|
|
34
|
+
keyword: "",
|
|
35
|
+
...body
|
|
36
|
+
},
|
|
37
|
+
config.accessToken
|
|
38
|
+
);
|
|
39
|
+
|
|
40
|
+
if (res && res.result) {
|
|
41
|
+
const data = res.data;
|
|
42
|
+
let rawList = [];
|
|
43
|
+
if (Array.isArray(data)) {
|
|
44
|
+
rawList = data;
|
|
45
|
+
} else if (data && Array.isArray(data.list)) {
|
|
46
|
+
rawList = data.list;
|
|
47
|
+
} else if (data && Array.isArray(data.data)) {
|
|
48
|
+
rawList = data.data;
|
|
49
|
+
} else if (data && typeof data === "object") {
|
|
50
|
+
rawList = Object.keys(data)
|
|
51
|
+
.filter((key) => /list$/i.test(key) && Array.isArray(data[key]))
|
|
52
|
+
.flatMap((key) =>
|
|
53
|
+
data[key].map((item) => ({
|
|
54
|
+
...item,
|
|
55
|
+
__group: key
|
|
56
|
+
}))
|
|
57
|
+
);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
if (!isMcp) {
|
|
61
|
+
console.log(JSON.stringify(rawList, null, 2));
|
|
62
|
+
}
|
|
63
|
+
return rawList;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
const msg = res && (res.returnInfo || res.message) ? (res.returnInfo || res.message) : "Unknown error";
|
|
67
|
+
throw new Error("Get IdentityProvider Failed: " + msg);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
module.exports = get;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
const cc = {}
|
|
2
|
+
cc.create = require("./create")
|
|
3
|
+
cc.delete = require("./delete")
|
|
4
|
+
cc.get = require("./get")
|
|
5
|
+
cc.download = require("./download")
|
|
6
|
+
cc.doc = require("./doc")
|
|
7
|
+
|
|
8
|
+
function main(action, argvs) {
|
|
9
|
+
cc[action](argvs)
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
module.exports = main;
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
const chalk = require('chalk');
|
|
2
|
+
const { postClass } = require("../../utils/http");
|
|
3
|
+
const { getPackageJson } = require("../../utils/config");
|
|
4
|
+
const inquirer = require('inquirer');
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* 获取用户视图ID
|
|
8
|
+
* @param {Object} config - 项目配置
|
|
9
|
+
* @returns {Promise<string>} 视图ID
|
|
10
|
+
*/
|
|
11
|
+
async function getUserViewId(config) {
|
|
12
|
+
const res = await postClass(
|
|
13
|
+
config.setupSvc + "/api/usermange/queryUser",
|
|
14
|
+
{},
|
|
15
|
+
config.accessToken
|
|
16
|
+
);
|
|
17
|
+
|
|
18
|
+
if (res && res.result && res.data) {
|
|
19
|
+
// 优先使用返回的 viewId
|
|
20
|
+
if (res.data.viewId) {
|
|
21
|
+
return res.data.viewId;
|
|
22
|
+
}
|
|
23
|
+
// 否则使用 viewList 中的第一个
|
|
24
|
+
if (Array.isArray(res.data.viewList) && res.data.viewList.length > 0) {
|
|
25
|
+
return res.data.viewList[0].id;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
throw new Error("未找到用户视图");
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* 查询可选用户列表
|
|
34
|
+
* @param {Object} config - 项目配置
|
|
35
|
+
* @param {string} viewId - 视图ID
|
|
36
|
+
* @param {string} keyword - 搜索关键词
|
|
37
|
+
* @returns {Promise<Array>} 用户列表
|
|
38
|
+
*/
|
|
39
|
+
async function queryUserList(config, viewId, keyword = '') {
|
|
40
|
+
const res = await postClass(
|
|
41
|
+
config.setupSvc + "/api/usermange/queryUserList",
|
|
42
|
+
{
|
|
43
|
+
start: 0,
|
|
44
|
+
limit: 10000,
|
|
45
|
+
viewId: viewId,
|
|
46
|
+
keyword: keyword,
|
|
47
|
+
notisusering: "true"
|
|
48
|
+
},
|
|
49
|
+
config.accessToken
|
|
50
|
+
);
|
|
51
|
+
|
|
52
|
+
if (res && res.result && res.data) {
|
|
53
|
+
return res.data.list || [];
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
throw new Error("查询用户列表失败");
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* 添加权限集分配用户
|
|
61
|
+
* 用法:cc add permission <projectPath> <permsetId> [userIds...]
|
|
62
|
+
* 如果不指定 userIds,会进入交互式选择
|
|
63
|
+
* @param {Array} argvs - 命令行参数数组
|
|
64
|
+
* @param {boolean} isMcp - 是否为MCP模式
|
|
65
|
+
* @returns {Promise<Object>} 添加结果
|
|
66
|
+
*/
|
|
67
|
+
async function add(argvs, isMcp = false) {
|
|
68
|
+
try {
|
|
69
|
+
const projectPath = argvs[2] || process.cwd();
|
|
70
|
+
const permsetId = argvs[3];
|
|
71
|
+
// 从第4个参数开始是用户ID
|
|
72
|
+
let userIds = argvs.slice(4);
|
|
73
|
+
|
|
74
|
+
if (!permsetId) {
|
|
75
|
+
console.error();
|
|
76
|
+
console.error(chalk.red('Error: 缺少权限集ID'));
|
|
77
|
+
console.error('用法: cc add permission <path> <permsetId> [userId1] [userId2] ...');
|
|
78
|
+
console.error('示例:');
|
|
79
|
+
console.error(' cc add permission . "cac20258F0E4ABBnTxwi" # 交互式选择用户');
|
|
80
|
+
console.error(' cc add permission . "cac20258F0E4ABBnTxwi" "00520260C00C6FEfsMnT" # 直接指定用户ID');
|
|
81
|
+
console.error();
|
|
82
|
+
throw new Error('缺少必需参数: permsetId');
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
const config = await getPackageJson(projectPath);
|
|
86
|
+
|
|
87
|
+
// 如果没有指定用户ID,进入交互式选择
|
|
88
|
+
if (userIds.length === 0) {
|
|
89
|
+
console.log();
|
|
90
|
+
console.log(chalk.blue('正在获取用户列表...'));
|
|
91
|
+
|
|
92
|
+
const viewId = await getUserViewId(config);
|
|
93
|
+
const userList = await queryUserList(config, viewId);
|
|
94
|
+
|
|
95
|
+
if (userList.length === 0) {
|
|
96
|
+
console.log(chalk.yellow("没有可用的用户"));
|
|
97
|
+
return { success: false, message: "没有可用的用户" };
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
// 交互式选择用户
|
|
101
|
+
const choices = userList.map(user => ({
|
|
102
|
+
name: `${user.name || '未命名'} (${user.loginname || ''}) - ${user.id}`,
|
|
103
|
+
value: user.id,
|
|
104
|
+
short: user.name || user.id
|
|
105
|
+
}));
|
|
106
|
+
|
|
107
|
+
const { selectedUsers } = await inquirer.prompt([
|
|
108
|
+
{
|
|
109
|
+
type: 'checkbox',
|
|
110
|
+
name: 'selectedUsers',
|
|
111
|
+
message: '请选择要分配的用户(使用空格键选择,回车确认):',
|
|
112
|
+
choices: choices,
|
|
113
|
+
validate: (input) => input.length > 0 || '请至少选择一个用户'
|
|
114
|
+
}
|
|
115
|
+
]);
|
|
116
|
+
|
|
117
|
+
userIds = selectedUsers;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
if (userIds.length === 0) {
|
|
121
|
+
console.log(chalk.yellow("未选择任何用户"));
|
|
122
|
+
return { success: false, message: "未选择任何用户" };
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
console.log();
|
|
126
|
+
console.log(chalk.blue(`正在为权限集 ${permsetId} 分配 ${userIds.length} 个用户...`));
|
|
127
|
+
|
|
128
|
+
const res = await postClass(
|
|
129
|
+
config.setupSvc + "/api/permissionGroup/addUsersetup",
|
|
130
|
+
{
|
|
131
|
+
id: permsetId,
|
|
132
|
+
ids: userIds.join(',')
|
|
133
|
+
},
|
|
134
|
+
config.accessToken
|
|
135
|
+
);
|
|
136
|
+
|
|
137
|
+
if (res && res.result) {
|
|
138
|
+
if (!isMcp) {
|
|
139
|
+
console.log();
|
|
140
|
+
console.log(chalk.green('✓ 用户分配成功'));
|
|
141
|
+
console.log(` 权限集ID: ${permsetId}`);
|
|
142
|
+
console.log(` 分配用户数: ${userIds.length}`);
|
|
143
|
+
console.log();
|
|
144
|
+
}
|
|
145
|
+
return {
|
|
146
|
+
success: true,
|
|
147
|
+
permsetId: permsetId,
|
|
148
|
+
userCount: userIds.length,
|
|
149
|
+
userIds: userIds
|
|
150
|
+
};
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
const msg = res && (res.returnInfo || res.message) ? (res.returnInfo || res.message) : "Unknown error";
|
|
154
|
+
throw new Error("分配用户失败: " + msg);
|
|
155
|
+
|
|
156
|
+
} catch (error) {
|
|
157
|
+
if (!isMcp) {
|
|
158
|
+
console.error(chalk.red("Error: " + error.message));
|
|
159
|
+
}
|
|
160
|
+
throw error;
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
module.exports = add;
|