| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -56,4 +56,24 @@ describe("unittests:: tsserver:: codeFix::", () => { | |||
| 56 | 56 | }); | |
| 57 | 57 | baselineTsserverLogs("codeFix", "install package when serialized", session); | |
| 58 | 58 | }); | |
| 59 | + | ||
| 60 | + it("install package rejects invalid package names", () => { | ||
| 61 | + const { host, session } = setup(); | ||
| 62 | + // A client could craft an applyCodeActionCommand with arbitrary package names. | ||
| 63 | + // The server must validate and reject names with invalid characters to prevent shell injection. | ||
| 64 | + for (const packageName of ["; echo 'hello' #", "react'test", "a/b/c"]) { | ||
| 65 | + session.executeCommandSeq<ts.server.protocol.ApplyCodeActionCommandRequest>({ | ||
| 66 | + command: ts.server.protocol.CommandTypes.ApplyCodeActionCommand, | ||
| 67 | + arguments: { | ||
| 68 | + command: { | ||
| 69 | + type: "install package", | ||
| 70 | + file: "/home/src/projects/project/src/file.ts", | ||
| 71 | + packageName, | ||
| 72 | + }, | ||
| 73 | + }, | ||
| 74 | + }); | ||
| 75 | + } | ||
| 76 | + host.runPendingInstalls(); | ||
| 77 | + baselineTsserverLogs("codeFix", "install package rejects invalid package names", session); | ||
| 78 | + }); | ||
| 59 | 79 | }); | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -239,6 +239,22 @@ export abstract class TypingsInstaller { | |||
| 239 | 239 | /** @internal */ | |
| 240 | 240 | installPackage(req: InstallPackageRequest): void { | |
| 241 | 241 | const { fileName, packageName, projectName, projectRootPath, id } = req; | |
| 242 | + const validationResult = JsTyping.validatePackageName(packageName); | ||
| 243 | + if (validationResult !== JsTyping.NameValidationResult.Ok) { | ||
| 244 | + const message = JsTyping.renderPackageNameValidationFailure(validationResult, packageName); | ||
| 245 | + if (this.log.isEnabled()) { | ||
| 246 | + this.log.writeLine(message); | ||
| 247 | + } | ||
| 248 | + const response: PackageInstalledResponse = { | ||
| 249 | + kind: ActionPackageInstalled, | ||
| 250 | + projectName, | ||
| 251 | + id, | ||
| 252 | + success: false, | ||
| 253 | + message, | ||
| 254 | + }; | ||
| 255 | + this.sendResponse(response); | ||
| 256 | + return; | ||
| 257 | + } | ||
| 242 | 258 | const cwd = forEachAncestorDirectory(getDirectoryPath(fileName), directory => { | |
| 243 | 259 | if (this.installTypingHost.fileExists(combinePaths(directory, "package.json"))) { | |
| 244 | 260 | return directory; | |
| Back | FazBrowse Home | New Git URL |
0 commit comments