Skip to content

Commit 4968ed4

Browse files
authored
feat: Sensitive information warning Linter (#143)
* feat: 敏感信息告警Linter * test: 敏感信息告警Linter test * fix: linter message * fix: linter code * fix: linter test code * fix: linter test code
1 parent 61df271 commit 4968ed4

File tree

9 files changed

+247
-90
lines changed

9 files changed

+247
-90
lines changed

media/yarn.lock

Lines changed: 2 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -5669,16 +5669,7 @@ string-convert@^0.2.0:
56695669
resolved "https://registry.npmmirror.com/string-convert/-/string-convert-0.2.1.tgz#6982cc3049fbb4cd85f8b24568b9d9bf39eeff97"
56705670
integrity sha512-u/1tdPl4yQnPBjnVrmdLo9gtuLvELKsAoRapekWggdiQNvvvum+jYF329d84NAa660KQw7pB2n36KrIKVoXa3A==
56715671

5672-
"string-width-cjs@npm:string-width@^4.2.0":
5673-
version "4.2.3"
5674-
resolved "https://registry.npmmirror.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010"
5675-
integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==
5676-
dependencies:
5677-
emoji-regex "^8.0.0"
5678-
is-fullwidth-code-point "^3.0.0"
5679-
strip-ansi "^6.0.1"
5680-
5681-
string-width@^4.1.0:
5672+
"string-width-cjs@npm:string-width@^4.2.0", string-width@^4.1.0:
56825673
version "4.2.3"
56835674
resolved "https://registry.npmmirror.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010"
56845675
integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==
@@ -5749,14 +5740,7 @@ string_decoder@^1.1.1:
57495740
dependencies:
57505741
safe-buffer "~5.2.0"
57515742

5752-
"strip-ansi-cjs@npm:strip-ansi@^6.0.1":
5753-
version "6.0.1"
5754-
resolved "https://registry.npmmirror.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9"
5755-
integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==
5756-
dependencies:
5757-
ansi-regex "^5.0.1"
5758-
5759-
strip-ansi@^6.0.0, strip-ansi@^6.0.1:
5743+
"strip-ansi-cjs@npm:strip-ansi@^6.0.1", strip-ansi@^6.0.0, strip-ansi@^6.0.1:
57605744
version "6.0.1"
57615745
resolved "https://registry.npmmirror.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9"
57625746
integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==

package.json

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,13 @@
1515
],
1616
"activationEvents": [
1717
"onStartFinished",
18-
"onWebviewPanel:alicloud-api-webview"
18+
"onWebviewPanel:alicloud-api-webview",
19+
"onLanguage:javascript",
20+
"onLanguage:typescript",
21+
"onLanguage:go",
22+
"onLanguage:php",
23+
"onLanguage:python",
24+
"onLanguage:java"
1925
],
2026
"main": "./dist/extension",
2127
"contributes": {
@@ -24,6 +30,10 @@
2430
"command": "alicloud.api.autoImport",
2531
"title": "导入依赖"
2632
},
33+
{
34+
"command": "alicloud.api.akSecurityHelper",
35+
"title": "凭据的安全使用方案"
36+
},
2737
{
2838
"command": "alicloud.api.feedback",
2939
"title": "反馈",

src/commands.ts

Lines changed: 12 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { PontManager } from "pontx-manager";
22
import * as _ from "lodash";
33
import * as vscode from "vscode";
44
import {
5+
AKHelperWithLanguage,
56
findAlicloudAPIConfig,
67
findInterface,
78
getSpecInfoFromName,
@@ -200,39 +201,6 @@ export class AlicloudApiCommands {
200201
});
201202
});
202203

203-
// vscode.commands.registerCommand("alicloud.api.regenerateAPIMocks", async (event) => {
204-
// const filePaths: string[] = (event.path || "")?.split("/");
205-
// const lastMocksIndex = filePaths.lastIndexOf("mocks");
206-
// const names = filePaths.slice(lastMocksIndex + 1);
207-
// names.push(names.pop().replace(".ts", ""));
208-
209-
// if (service.pontManager.localPontSpecs?.[0]?.name) {
210-
// showProgress("重新生成 API Mocks", service.pontManager, async (log) => {
211-
// log("代码生成中...");
212-
// await wait(100);
213-
214-
// let specName, modName, apiName;
215-
// if (names.length === 3) {
216-
// [specName, modName, apiName] = names;
217-
// } else {
218-
// [specName, apiName] = names;
219-
// }
220-
// const mocksPlugin = await service.pontManager.innerManagerConfig.plugins.mocks?.instance;
221-
// const mocksOptions = await service.pontManager.innerManagerConfig.plugins.mocks?.options;
222-
// const mocksCode = await mocksPlugin.getAPIMockCode(
223-
// service.pontManager,
224-
// mocksOptions,
225-
// apiName,
226-
// modName,
227-
// specName,
228-
// );
229-
// fs.writeFileSync(event.path, mocksCode, "utf-8");
230-
231-
// log("API Mocks 生成成功!");
232-
// vscode.window.showInformationMessage("API Mocks生成成功!");
233-
// });
234-
// }
235-
// });
236204
vscode.commands.registerCommand("alicloud.api.autoImport", (...argus) => {
237205
const diagnostic = argus[0];
238206
const missingDep = argus[1];
@@ -243,6 +211,17 @@ export class AlicloudApiCommands {
243211
}
244212
});
245213

214+
vscode.commands.registerCommand("alicloud.api.akSecurityHelper", (...argus) => {
215+
const document = argus[0];
216+
if (AKHelperWithLanguage[document.languageId]) {
217+
vscode.env.openExternal(vscode.Uri.parse(AKHelperWithLanguage[document.languageId]));
218+
} else {
219+
vscode.env.openExternal(
220+
vscode.Uri.parse("https://help.aliyun.com/zh/sdk/developer-reference/ak-security-scheme"),
221+
);
222+
}
223+
});
224+
246225
vscode.commands.registerCommand("alicloud.api.fetchRemote", (config) => {
247226
const pontManager = service.pontManager;
248227

@@ -329,23 +308,5 @@ export class AlicloudApiCommands {
329308
spec: spec?.apis?.[`${result.apiKey}`],
330309
});
331310
});
332-
// vscode.commands.registerTextEditorCommand("alicloud.api.viewMocks", async (editor, edit) => {
333-
// const isSingleSpec = PontManager.checkIsSingleSpec(service.pontManager);
334-
// const result = (await findInterface(editor, !isSingleSpec, service.pontManager)) || ({} as any);
335-
// const spec = PontManager.getSpec(service.pontManager, result.specName);
336-
337-
// if (!result.apiName) {
338-
// vscode.window.showErrorMessage("未找到该 OpenAPI");
339-
// return;
340-
// }
341-
342-
// const namespace = [result.specName, result.modName, result.apiName].filter((id) => id).join("/");
343-
// const mocksFilePath = path.join(service.pontManager.innerManagerConfig.outDir, "mocks", namespace + ".ts");
344-
// vscode.commands.executeCommand("vscode.open", vscode.Uri.file(mocksFilePath));
345-
// });
346-
347-
// vscode.commands.registerCommand('alicloud.api.refreshPontExplorer', () => {
348-
// service.treeDataProvider.refresh();
349-
// });
350311
}
351312
}

src/extension.ts

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,4 @@
11
"use strict";
2-
// The module 'vscode' contains the VS Code extensibility API
3-
// Import the module and reference it with the alias vscode in your code below
42
import { PontManager } from "pontx-manager";
53
import PontMetaFetchPlugin from "pontx-meta-fetch-plugin";
64
import * as vscode from "vscode";
@@ -16,12 +14,9 @@ import autoCompletion from "./provider/autoCompletion";
1614
import autofix from "./provider/autofix";
1715
import hoverInfo from "./provider/hoverProvider";
1816
import { getProfileInfoInstance } from "./profileManager";
17+
import { registerLinter } from "./provider/linter";
1918

2019
export async function activate(context: vscode.ExtensionContext) {
21-
// if (!vscode.workspace.rootPath) {
22-
// return;
23-
// }
24-
// registerConfigSchema(context);
2520
const pontxConfig = await findAlicloudAPIConfig(context);
2621

2722
if (!pontxConfig) {
@@ -87,6 +82,8 @@ export async function activate(context: vscode.ExtensionContext) {
8782
autofix(context);
8883
// hover提示
8984
hoverInfo(context);
85+
// 代码诊断
86+
registerLinter(context);
9087
}
9188
} catch (e) {
9289
vscode.window.showErrorMessage(e.message);

src/provider/autofix.ts

Lines changed: 24 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,10 @@
22
* @description: Quick fix need to be used with a Linter
33
*/
44
import * as vscode from "vscode";
5-
import { containsAnySubstring, fileSel, getSpecInfoFromName } from "../utils";
5+
import { containsAnySubstring, fileSel, getSpecInfoFromName, SDKLanguageLabel } from "../utils";
66
import { getDepsByLanguage } from "../common/generateImport";
77
import { alicloudAPIMessageService } from "../Service";
8+
import { LintRules } from "./linter";
89

910
class CodeActionProvider {
1011
provideCodeActions(
@@ -21,16 +22,13 @@ class CodeActionProvider {
2122
const document = editor.document;
2223
const errorText = document.getText(item?.range);
2324
const service = alicloudAPIMessageService;
24-
const products = service.pontManager.localPontSpecs
25-
.map((pontSpec) => {
26-
return getSpecInfoFromName(pontSpec?.name)[0];
27-
})
25+
const products = service.pontManager.localPontSpecs.map((pontSpec) => {
26+
return getSpecInfoFromName(pontSpec?.name)[0];
27+
});
2828

29+
// 未导入依赖的诊断建议
2930
if (getDepsByLanguage(errorText, item.range)?.includes(errorText) || containsAnySubstring(errorText, products)) {
30-
const autoImportAction = new vscode.CodeAction(
31-
item.message + "导入依赖",
32-
vscode.CodeActionKind.QuickFix,
33-
);
31+
const autoImportAction = new vscode.CodeAction(item.message + "导入依赖", vscode.CodeActionKind.QuickFix);
3432
const newDiagnostic = new vscode.Diagnostic(item.range, "importLists", vscode.DiagnosticSeverity.Error);
3533
// 自动修复命令注册
3634
autoImportAction.command = {
@@ -40,6 +38,23 @@ class CodeActionProvider {
4038
};
4139
return autoImportAction;
4240
}
41+
42+
// AccessKey 可能泄露的诊断建议
43+
const lintResult = LintRules?.find((rule) => rule.source === item.source);
44+
if (lintResult) {
45+
// 自动修复命令注册
46+
const codeAction = new vscode.CodeAction(
47+
`${lintResult.methods[0]?.title}${SDKLanguageLabel[document.languageId] || "阿里云 SDK"})`,
48+
vscode.CodeActionKind.QuickFix,
49+
);
50+
codeAction.command = {
51+
title: `${lintResult.methods[0]?.title}${SDKLanguageLabel[document.languageId] || "阿里云 SDK"})`,
52+
command: lintResult.methods[0]?.command,
53+
arguments: [document],
54+
};
55+
56+
return codeAction;
57+
}
4358
});
4459

4560
return result;

src/provider/linter.ts

Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
/**
2+
* @description: Linter of the Code
3+
*/
4+
import * as vscode from "vscode";
5+
import { fileSel } from "../utils";
6+
7+
class Rule {
8+
LintName: string;
9+
pattern: string;
10+
message: string;
11+
source: string;
12+
information: string;
13+
methods: Array<{
14+
title: string;
15+
command: string;
16+
}>;
17+
}
18+
export const LintRules: Array<Rule> = [
19+
{
20+
LintName: "AccessKey-NewAK",
21+
source: "Alicloud Access Key Lint",
22+
information: "在此处透露了 Access Key。",
23+
pattern: `^LTAI(?=.*[A-Z])(?=.*[a-z])(?=.*\\d)[A-Za-z\\d]{12}$|^LTAI(?=.*[A-Z])(?=.*[a-z])(?=.*\\d)[A-Za-z\\d]{16}$|^LTAI(?=.*[A-Z])(?=.*[a-z])(?=.*\\d)[A-Za-z\\d]{18}$|^LTAI(?=.*[A-Z])(?=.*[a-z])(?=.*\\d)[A-Za-z\\d]{20}$|^LTAI(?=.*[A-Z])(?=.*[a-z])(?=.*\\d)[A-Za-z\\d]{22}$`,
24+
message: "在工程中硬编码 Access Key ID/Secret 容易发生凭证数据泄漏,并进而威胁到您账号下所有资源的安全性。",
25+
methods: [{ title: "凭据的安全使用方案", command: "alicloud.api.akSecurityHelper" }],
26+
},
27+
{
28+
LintName: "AccessSecret",
29+
source: "Alicloud AccessKey Lint",
30+
information: "在此处透露了 Access Secret。",
31+
pattern: `[a-zA-Z0-9]{30}`,
32+
message: "在工程中硬编码 Access Key ID/Secret 容易发生凭证数据泄漏,并进而威胁到您账号下所有资源的安全性。",
33+
methods: [{ title: "凭据的安全使用方案", command: "alicloud.api.akSecurityHelper" }],
34+
},
35+
];
36+
37+
export function searchCode(
38+
diagnosticCollection: vscode.Diagnostic[],
39+
rule: Rule,
40+
text: string,
41+
document: vscode.TextDocument,
42+
) {
43+
const regex = new RegExp(rule.pattern, "gi");
44+
const strRegex = new RegExp(`[\'\"\`](.*?)[\'\"\`]`, "gi");
45+
let strMatch;
46+
let matchTexts = [];
47+
while ((strMatch = strRegex.exec(text)) !== null) {
48+
const range = new vscode.Range(document.positionAt(strMatch.index), document.positionAt(strRegex.lastIndex));
49+
const matchText = document.getText(range);
50+
const pureString = matchText.substring(1, matchText.length - 1);
51+
const isMatch = regex.test(pureString);
52+
if (isMatch) {
53+
matchTexts.push(pureString);
54+
diagnosticCollection.push({
55+
code: "",
56+
message: rule.message,
57+
range: range,
58+
severity: vscode.DiagnosticSeverity.Error,
59+
source: rule.source,
60+
relatedInformation: [
61+
new vscode.DiagnosticRelatedInformation(new vscode.Location(document.uri, range), rule.information),
62+
],
63+
});
64+
}
65+
}
66+
return matchTexts;
67+
}
68+
69+
export async function updateDiagnostics(
70+
document: vscode.TextDocument,
71+
collection: vscode.DiagnosticCollection,
72+
): Promise<void> {
73+
if ((fileSel as any)?.find((sel) => sel.language === document.languageId)) {
74+
const text = document.getText();
75+
76+
let diagnosticCollection: vscode.Diagnostic[] = [];
77+
78+
LintRules.forEach((rule) => {
79+
searchCode(diagnosticCollection, rule, text, document);
80+
});
81+
82+
collection.set(document.uri, diagnosticCollection);
83+
} else {
84+
collection.clear();
85+
}
86+
}
87+
88+
export async function registerLinter(context: vscode.ExtensionContext) {
89+
// 插件诊断器
90+
const collection = vscode.languages.createDiagnosticCollection("alicloud-linter");
91+
if (vscode.window.activeTextEditor) {
92+
updateDiagnostics(vscode.window.activeTextEditor.document, collection);
93+
}
94+
context.subscriptions.push(
95+
vscode.window.onDidChangeActiveTextEditor((editor) => {
96+
if (editor) {
97+
updateDiagnostics(editor.document, collection);
98+
}
99+
}),
100+
);
101+
context.subscriptions.push(
102+
vscode.workspace.onDidChangeTextDocument((editor) => {
103+
if (editor) {
104+
updateDiagnostics(editor.document, collection);
105+
}
106+
}),
107+
);
108+
}

src/test/suite/extension.test.ts

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -25,9 +25,4 @@ suite("Extension Test Suite", () => {
2525
console.log("alicloud.api.restart successfully executed");
2626
assert.strictEqual("ok", result);
2727
});
28-
29-
test("Sample test", () => {
30-
assert.strictEqual(-1, [1, 2, 3].indexOf(5));
31-
assert.strictEqual(-1, [1, 2, 3].indexOf(0));
32-
});
3328
});

0 commit comments

Comments
 (0)