Skip to content

feat: Sensitive information warning Linter #143

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 8 commits into from
Sep 3, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 2 additions & 18 deletions media/yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -5669,16 +5669,7 @@ string-convert@^0.2.0:
resolved "https://registry.npmmirror.com/string-convert/-/string-convert-0.2.1.tgz#6982cc3049fbb4cd85f8b24568b9d9bf39eeff97"
integrity sha512-u/1tdPl4yQnPBjnVrmdLo9gtuLvELKsAoRapekWggdiQNvvvum+jYF329d84NAa660KQw7pB2n36KrIKVoXa3A==

"string-width-cjs@npm:string-width@^4.2.0":
version "4.2.3"
resolved "https://registry.npmmirror.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010"
integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==
dependencies:
emoji-regex "^8.0.0"
is-fullwidth-code-point "^3.0.0"
strip-ansi "^6.0.1"

string-width@^4.1.0:
"string-width-cjs@npm:string-width@^4.2.0", string-width@^4.1.0:
version "4.2.3"
resolved "https://registry.npmmirror.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010"
integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==
Expand Down Expand Up @@ -5749,14 +5740,7 @@ string_decoder@^1.1.1:
dependencies:
safe-buffer "~5.2.0"

"strip-ansi-cjs@npm:strip-ansi@^6.0.1":
version "6.0.1"
resolved "https://registry.npmmirror.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9"
integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==
dependencies:
ansi-regex "^5.0.1"

strip-ansi@^6.0.0, strip-ansi@^6.0.1:
"strip-ansi-cjs@npm:strip-ansi@^6.0.1", strip-ansi@^6.0.0, strip-ansi@^6.0.1:
version "6.0.1"
resolved "https://registry.npmmirror.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9"
integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==
Expand Down
12 changes: 11 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,13 @@
],
"activationEvents": [
"onStartFinished",
"onWebviewPanel:alicloud-api-webview"
"onWebviewPanel:alicloud-api-webview",
"onLanguage:javascript",
"onLanguage:typescript",
"onLanguage:go",
"onLanguage:php",
"onLanguage:python",
"onLanguage:java"
],
"main": "./dist/extension",
"contributes": {
Expand All @@ -24,6 +30,10 @@
"command": "alicloud.api.autoImport",
"title": "导入依赖"
},
{
"command": "alicloud.api.akSecurityHelper",
"title": "凭据的安全使用方案"
},
{
"command": "alicloud.api.feedback",
"title": "反馈",
Expand Down
63 changes: 12 additions & 51 deletions src/commands.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { PontManager } from "pontx-manager";
import * as _ from "lodash";
import * as vscode from "vscode";
import {
AKHelperWithLanguage,
findAlicloudAPIConfig,
findInterface,
getSpecInfoFromName,
Expand Down Expand Up @@ -200,39 +201,6 @@ export class AlicloudApiCommands {
});
});

// vscode.commands.registerCommand("alicloud.api.regenerateAPIMocks", async (event) => {
// const filePaths: string[] = (event.path || "")?.split("/");
// const lastMocksIndex = filePaths.lastIndexOf("mocks");
// const names = filePaths.slice(lastMocksIndex + 1);
// names.push(names.pop().replace(".ts", ""));

// if (service.pontManager.localPontSpecs?.[0]?.name) {
// showProgress("重新生成 API Mocks", service.pontManager, async (log) => {
// log("代码生成中...");
// await wait(100);

// let specName, modName, apiName;
// if (names.length === 3) {
// [specName, modName, apiName] = names;
// } else {
// [specName, apiName] = names;
// }
// const mocksPlugin = await service.pontManager.innerManagerConfig.plugins.mocks?.instance;
// const mocksOptions = await service.pontManager.innerManagerConfig.plugins.mocks?.options;
// const mocksCode = await mocksPlugin.getAPIMockCode(
// service.pontManager,
// mocksOptions,
// apiName,
// modName,
// specName,
// );
// fs.writeFileSync(event.path, mocksCode, "utf-8");

// log("API Mocks 生成成功!");
// vscode.window.showInformationMessage("API Mocks生成成功!");
// });
// }
// });
vscode.commands.registerCommand("alicloud.api.autoImport", (...argus) => {
const diagnostic = argus[0];
const missingDep = argus[1];
Expand All @@ -243,6 +211,17 @@ export class AlicloudApiCommands {
}
});

vscode.commands.registerCommand("alicloud.api.akSecurityHelper", (...argus) => {
const document = argus[0];
if (AKHelperWithLanguage[document.languageId]) {
vscode.env.openExternal(vscode.Uri.parse(AKHelperWithLanguage[document.languageId]));
} else {
vscode.env.openExternal(
vscode.Uri.parse("https://help.aliyun.com/zh/sdk/developer-reference/ak-security-scheme"),
);
}
});

vscode.commands.registerCommand("alicloud.api.fetchRemote", (config) => {
const pontManager = service.pontManager;

Expand Down Expand Up @@ -329,23 +308,5 @@ export class AlicloudApiCommands {
spec: spec?.apis?.[`${result.apiKey}`],
});
});
// vscode.commands.registerTextEditorCommand("alicloud.api.viewMocks", async (editor, edit) => {
// const isSingleSpec = PontManager.checkIsSingleSpec(service.pontManager);
// const result = (await findInterface(editor, !isSingleSpec, service.pontManager)) || ({} as any);
// const spec = PontManager.getSpec(service.pontManager, result.specName);

// if (!result.apiName) {
// vscode.window.showErrorMessage("未找到该 OpenAPI");
// return;
// }

// const namespace = [result.specName, result.modName, result.apiName].filter((id) => id).join("/");
// const mocksFilePath = path.join(service.pontManager.innerManagerConfig.outDir, "mocks", namespace + ".ts");
// vscode.commands.executeCommand("vscode.open", vscode.Uri.file(mocksFilePath));
// });

// vscode.commands.registerCommand('alicloud.api.refreshPontExplorer', () => {
// service.treeDataProvider.refresh();
// });
}
}
9 changes: 3 additions & 6 deletions src/extension.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
"use strict";
// The module 'vscode' contains the VS Code extensibility API
// Import the module and reference it with the alias vscode in your code below
import { PontManager } from "pontx-manager";
import PontMetaFetchPlugin from "pontx-meta-fetch-plugin";
import * as vscode from "vscode";
Expand All @@ -16,12 +14,9 @@ import autoCompletion from "./provider/autoCompletion";
import autofix from "./provider/autofix";
import hoverInfo from "./provider/hoverProvider";
import { getProfileInfoInstance } from "./profileManager";
import { registerLinter } from "./provider/linter";

export async function activate(context: vscode.ExtensionContext) {
// if (!vscode.workspace.rootPath) {
// return;
// }
// registerConfigSchema(context);
const pontxConfig = await findAlicloudAPIConfig(context);

if (!pontxConfig) {
Expand Down Expand Up @@ -87,6 +82,8 @@ export async function activate(context: vscode.ExtensionContext) {
autofix(context);
// hover提示
hoverInfo(context);
// 代码诊断
registerLinter(context);
}
} catch (e) {
vscode.window.showErrorMessage(e.message);
Expand Down
33 changes: 24 additions & 9 deletions src/provider/autofix.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,10 @@
* @description: Quick fix need to be used with a Linter
*/
import * as vscode from "vscode";
import { containsAnySubstring, fileSel, getSpecInfoFromName } from "../utils";
import { containsAnySubstring, fileSel, getSpecInfoFromName, SDKLanguageLabel } from "../utils";
import { getDepsByLanguage } from "../common/generateImport";
import { alicloudAPIMessageService } from "../Service";
import { LintRules } from "./linter";

class CodeActionProvider {
provideCodeActions(
Expand All @@ -21,16 +22,13 @@ class CodeActionProvider {
const document = editor.document;
const errorText = document.getText(item?.range);
const service = alicloudAPIMessageService;
const products = service.pontManager.localPontSpecs
.map((pontSpec) => {
return getSpecInfoFromName(pontSpec?.name)[0];
})
const products = service.pontManager.localPontSpecs.map((pontSpec) => {
return getSpecInfoFromName(pontSpec?.name)[0];
});

// 未导入依赖的诊断建议
if (getDepsByLanguage(errorText, item.range)?.includes(errorText) || containsAnySubstring(errorText, products)) {
const autoImportAction = new vscode.CodeAction(
item.message + "导入依赖",
vscode.CodeActionKind.QuickFix,
);
const autoImportAction = new vscode.CodeAction(item.message + "导入依赖", vscode.CodeActionKind.QuickFix);
const newDiagnostic = new vscode.Diagnostic(item.range, "importLists", vscode.DiagnosticSeverity.Error);
// 自动修复命令注册
autoImportAction.command = {
Expand All @@ -40,6 +38,23 @@ class CodeActionProvider {
};
return autoImportAction;
}

// AccessKey 可能泄露的诊断建议
const lintResult = LintRules?.find((rule) => rule.source === item.source);
if (lintResult) {
// 自动修复命令注册
const codeAction = new vscode.CodeAction(
`${lintResult.methods[0]?.title}(${SDKLanguageLabel[document.languageId] || "阿里云 SDK"})`,
vscode.CodeActionKind.QuickFix,
);
codeAction.command = {
title: `${lintResult.methods[0]?.title}(${SDKLanguageLabel[document.languageId] || "阿里云 SDK"})`,
command: lintResult.methods[0]?.command,
arguments: [document],
};

return codeAction;
}
});

return result;
Expand Down
108 changes: 108 additions & 0 deletions src/provider/linter.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
/**
* @description: Linter of the Code
*/
import * as vscode from "vscode";
import { fileSel } from "../utils";

class Rule {
LintName: string;
pattern: string;
message: string;
source: string;
information: string;
methods: Array<{
title: string;
command: string;
}>;
}
export const LintRules: Array<Rule> = [
{
LintName: "AccessKey-NewAK",
source: "Alicloud Access Key Lint",
information: "在此处透露了 Access Key。",
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}$`,
message: "在工程中硬编码 Access Key ID/Secret 容易发生凭证数据泄漏,并进而威胁到您账号下所有资源的安全性。",
methods: [{ title: "凭据的安全使用方案", command: "alicloud.api.akSecurityHelper" }],
},
{
LintName: "AccessSecret",
source: "Alicloud AccessKey Lint",
information: "在此处透露了 Access Secret。",
pattern: `[a-zA-Z0-9]{30}`,
message: "在工程中硬编码 Access Key ID/Secret 容易发生凭证数据泄漏,并进而威胁到您账号下所有资源的安全性。",
methods: [{ title: "凭据的安全使用方案", command: "alicloud.api.akSecurityHelper" }],
},
];

export function searchCode(
diagnosticCollection: vscode.Diagnostic[],
rule: Rule,
text: string,
document: vscode.TextDocument,
) {
const regex = new RegExp(rule.pattern, "gi");
const strRegex = new RegExp(`[\'\"\`](.*?)[\'\"\`]`, "gi");
let strMatch;
let matchTexts = [];
while ((strMatch = strRegex.exec(text)) !== null) {
const range = new vscode.Range(document.positionAt(strMatch.index), document.positionAt(strRegex.lastIndex));
const matchText = document.getText(range);
const pureString = matchText.substring(1, matchText.length - 1);
const isMatch = regex.test(pureString);
if (isMatch) {
matchTexts.push(pureString);
diagnosticCollection.push({
code: "",
message: rule.message,
range: range,
severity: vscode.DiagnosticSeverity.Error,
source: rule.source,
relatedInformation: [
new vscode.DiagnosticRelatedInformation(new vscode.Location(document.uri, range), rule.information),
],
});
}
}
return matchTexts;
}

export async function updateDiagnostics(
document: vscode.TextDocument,
collection: vscode.DiagnosticCollection,
): Promise<void> {
if ((fileSel as any)?.find((sel) => sel.language === document.languageId)) {
const text = document.getText();

let diagnosticCollection: vscode.Diagnostic[] = [];

LintRules.forEach((rule) => {
searchCode(diagnosticCollection, rule, text, document);
});

collection.set(document.uri, diagnosticCollection);
} else {
collection.clear();
}
}

export async function registerLinter(context: vscode.ExtensionContext) {
// 插件诊断器
const collection = vscode.languages.createDiagnosticCollection("alicloud-linter");
if (vscode.window.activeTextEditor) {
updateDiagnostics(vscode.window.activeTextEditor.document, collection);
}
context.subscriptions.push(
vscode.window.onDidChangeActiveTextEditor((editor) => {
if (editor) {
updateDiagnostics(editor.document, collection);
}
}),
);
context.subscriptions.push(
vscode.workspace.onDidChangeTextDocument((editor) => {
if (editor) {
updateDiagnostics(editor.document, collection);
}
}),
);
}
5 changes: 0 additions & 5 deletions src/test/suite/extension.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,4 @@ suite("Extension Test Suite", () => {
console.log("alicloud.api.restart successfully executed");
assert.strictEqual("ok", result);
});

test("Sample test", () => {
assert.strictEqual(-1, [1, 2, 3].indexOf(5));
assert.strictEqual(-1, [1, 2, 3].indexOf(0));
});
});
Loading
Loading