Skip to content

Commit b83d6e2

Browse files
committed
workable
1 parent 69592ce commit b83d6e2

31 files changed

Lines changed: 4261 additions & 4122 deletions

package-lock.json

Lines changed: 2243 additions & 1484 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 10 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@
3333
},
3434
"icon": "socket-square.png",
3535
"activationEvents": [
36-
"workspaceContains:**/[pP][aA][cC][kK][aA][gG][eE].[jJ][sS][oO][nN]",
36+
"workspaceConatains:**/[pP][aA][cC][kK][aA][gG][eE].[jJ][sS][oO][nN]",
3737
"workspaceContains:**/[sS][oO][cC][kK][eE][tT].[yY][mM][lL]",
3838
"workspaceContains:**/[rR][eE][qQ][uU][iI][rR][eE][mM][eE][nN][tT][sS].[tT][xX][tT]",
3939
"workspaceContains:**/[pP][yY][pP][rR][oO][jJ][eE][cC][tT].[tT][oO][mM][lL]",
@@ -48,67 +48,19 @@
4848
"main": "./out/main.js",
4949
"homepage": "https://socket.dev",
5050
"contributes": {
51-
"commands": [
52-
{
53-
"command": "socket-security.runReport",
54-
"category": "Socket Security",
55-
"title": "Run Report",
56-
"enablement": "workspaceFolderCount >= 1"
57-
}
58-
],
5951
"configuration": {
6052
"title": "Socket Security",
6153
"properties": {
62-
"socket-security.minIssueLevel": {
63-
"order": 1,
64-
"type": "string",
65-
"default": "low",
66-
"enum": [
67-
"critical",
68-
"high",
69-
"middle",
70-
"low"
71-
],
72-
"description": "Hide all issues that are less important than this level. Note some issues are hidden by default so you may also wish to enable showing all issue types still."
73-
},
74-
"socket-security.errorOverlayThreshold": {
75-
"order": 2,
76-
"type": "number",
77-
"default": 50,
78-
"minimum": 0,
79-
"maximum": 100,
80-
"description": "Show error overlay for any import of a package with a summary score less than this value.",
81-
"examples": [
82-
50
83-
]
84-
},
85-
"socket-security.warnOverlayThreshold": {
86-
"order": 3,
87-
"type": "number",
88-
"default": 80,
89-
"minimum": 0,
90-
"maximum": 100,
91-
"description": "Show overlay for any import of a package with a summary score less than this value.",
92-
"examples": [
93-
80
94-
]
95-
},
96-
"socket-security.reportsEnabled": {
97-
"order": 4,
98-
"type": "boolean",
99-
"default": true,
100-
"description": "Create reports from package manifest files (package.json / package-lock.json) that require sending data remotely. Disabling this will disable all issues but keep scores listed."
101-
},
10254
"socket-security.pythonInterpreter": {
103-
"order": 5,
55+
"order": 1,
10456
"type": "string",
10557
"description": "Path to a Python interpreter to use for Socket dependency analysis.",
10658
"examples": [
10759
"/usr/bin/python"
10860
]
10961
},
11062
"socket-security.goExecutable": {
111-
"order": 6,
63+
"order": 2,
11264
"type": "string",
11365
"description": "Path to a Go executable to use for Socket dependency analysis.",
11466
"examples": [
@@ -124,7 +76,7 @@
12476
"publisher": "SocketSecurity",
12577
"scripts": {
12678
"vscode:prepublish": "npm run esbuild -- --minify",
127-
"esbuild-base": "esbuild --bundle --external:vscode --loader:.wasm=binary --loader:.go=file --outdir=out/ --platform=node --sourcemap",
79+
"esbuild-base": "esbuild --bundle --external:vscode --loader:.wasm=binary --loader:.go=file --loader:.py=text --outdir=out/ --platform=node --sourcemap",
12880
"esbuild": "npm run esbuild-base -- --format=cjs main=src/extension.ts",
12981
"test-compile": "tsc -p ./",
13082
"lint": "eslint \"src/**/*.ts\"",
@@ -133,23 +85,18 @@
13385
},
13486
"dependencies": {
13587
"@babel/parser": "^7.20.7",
88+
"@babel/traverse": "^7.20.7",
89+
"@babel/types": "^7.20.7",
13690
"@socketsecurity/config": "^2.0.0",
13791
"@socketsecurity/registry": "^1.0.66",
138-
"@vscode/vsce": "^2.20.1",
139-
"acorn-walk": "^8.2.0",
140-
"antlr4": "^4.13.0",
141-
"ast-types": "^0.14.2",
142-
"form-data-encoder": "^3.0.0",
143-
"formdata-node": "^5.0.1",
92+
"@vscode/python-extension": "^1.0.5",
93+
"@vscode/vsce": "^3.6.0",
14494
"ini": "^3.0.1",
14595
"json-to-ast": "^2.1.0",
146-
"micromatch": "^4.0.8",
147-
"octokit": "^3.1.2",
148-
"safe-stable-stringify": "^2.4.1",
149-
"semver": "^7.5.2",
150-
"yaml": "^2.2.2"
96+
"octokit": "^3.1.2"
15197
},
15298
"devDependencies": {
99+
"@types/babel__traverse": "^7.20.7",
153100
"@types/ini": "^1.3.31",
154101
"@types/json-to-ast": "^2.1.2",
155102
"@types/micromatch": "^4.0.2",

src/api.ts

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
/////////
2+
// DESIGN NOTES
3+
/////////
4+
//
5+
// We pass apiKeys rather than shared state to avoid certain races, so if a
6+
// workflow starts with 1 API key it is inconvenient to grab an implicitly
7+
// new api key in the middle of the workflow
8+
//
9+
function toAuthHeader(apiKey: string) {
10+
return `Basic ${Buffer.from(`${apiKey}:`).toString('base64url')}`
11+
}
12+
export async function getQuota(apiKey: string) {
13+
const res = await fetch('https://api.socket.dev/v0/settings', {
14+
method: 'POST',
15+
headers: {
16+
Authorization: toAuthHeader(apiKey),
17+
'Content-Type': 'application/json'
18+
}
19+
})
20+
if (res.ok) {
21+
return res.json()
22+
} else {
23+
throw new Error(await res.text())
24+
}
25+
}

src/auth.ts

Lines changed: 183 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,183 @@
1+
import vscode from 'vscode'
2+
import os from 'os'
3+
import path from 'path'
4+
import { DIAGNOSTIC_SOURCE_STR, EXTENSION_PREFIX } from './util'
5+
import { getQuota } from './api'
6+
7+
export async function activate(context: vscode.ExtensionContext, disposables?: Array<vscode.Disposable>) {
8+
//#region file path/watching
9+
// responsible for watching files to know when to sync from disk
10+
let dataHome = process.platform === 'win32'
11+
? process.env['LOCALAPPDATA']
12+
: process.env['XDG_DATA_HOME']
13+
14+
if (!dataHome) {
15+
if (process.platform === 'win32') throw new Error('missing %LOCALAPPDATA%')
16+
const home = os.homedir()
17+
dataHome = path.join(home, ...(process.platform === 'darwin'
18+
? ['Library', 'Application Support']
19+
: ['.local', 'share']
20+
))
21+
}
22+
23+
let defaultSettingsPath = path.join(dataHome, 'socket', 'settings')
24+
let settingsPath = vscode.workspace.getConfiguration(EXTENSION_PREFIX)
25+
.get('settingsFile', defaultSettingsPath)
26+
//#endregion
27+
//#region session sync
28+
// responsible for keeping disk an mem in sync
29+
const PUBLIC_TOKEN = 'sktsec_t_--RAN5U4ivauy4w37-6aoKyYPDt5ZbaT5JBVMqiwKo_api'
30+
let liveSessions: Map<vscode.AuthenticationSession['accessToken'], vscode.AuthenticationSession> = new Map()
31+
const emitter = new vscode.EventEmitter<vscode.AuthenticationProviderAuthenticationSessionsChangeEvent>()
32+
async function syncLiveSessionsFromDisk() {
33+
const settings_on_disk = JSON.parse(Buffer.from(
34+
new TextDecoder().decode(await vscode.workspace.fs.readFile(vscode.Uri.file(settingsPath))),
35+
'base64'
36+
).toString('utf8'))
37+
const {
38+
apiKey
39+
} = settings_on_disk
40+
const sessionOnDisk: typeof liveSessions = new Map<vscode.AuthenticationSession['accessToken'], vscode.AuthenticationSession>()
41+
if (apiKey) {
42+
sessionOnDisk.set(
43+
apiKey,
44+
{
45+
accessToken: apiKey,
46+
id: apiKey,
47+
account: {
48+
id: apiKey,
49+
label: `API Key for ${DIAGNOSTIC_SOURCE_STR}`
50+
},
51+
scopes: [],
52+
}
53+
)
54+
}
55+
let added: Array<vscode.AuthenticationSession> = []
56+
let changed: Array<vscode.AuthenticationSession> = []
57+
let removed: Array<vscode.AuthenticationSession> = []
58+
for (const diskSession of sessionOnDisk.values()) {
59+
// already have this access token in mem session
60+
if (liveSessions.has(diskSession.accessToken)) {
61+
const liveSession = liveSessions.get(diskSession.accessToken)
62+
liveSessions.delete(diskSession.accessToken)
63+
// mem has same as what is on disk
64+
if (JSON.stringify(liveSession) !== JSON.stringify(diskSession)) {
65+
continue
66+
}
67+
changed.push(diskSession)
68+
} else {
69+
added.push(diskSession)
70+
}
71+
}
72+
for (const liveSessionWithoutDiskSession of liveSessions.values()) {
73+
removed.push(liveSessionWithoutDiskSession)
74+
}
75+
liveSessions = sessionOnDisk
76+
if (added.length + changed.length + removed.length > 0) {
77+
emitter.fire({
78+
added,
79+
changed,
80+
removed
81+
})
82+
}
83+
}
84+
async function syncLiveSessionsToDisk() {
85+
const contents = Buffer.from(
86+
JSON.stringify(
87+
Array.from(liveSessions.values(), s => ({
88+
apiKey: s.accessToken
89+
})),
90+
null,
91+
2
92+
)
93+
).toString('base64')
94+
return vscode.workspace.fs.writeFile(vscode.Uri.file(settingsPath), new TextEncoder().encode(contents))
95+
}
96+
await syncLiveSessionsFromDisk()
97+
//#endregion
98+
//#region service glue
99+
const service = vscode.authentication.registerAuthenticationProvider(`${EXTENSION_PREFIX}`, `${DIAGNOSTIC_SOURCE_STR}`, {
100+
onDidChangeSessions(fn) {
101+
return emitter.event(fn)
102+
},
103+
async getSessions(scopes: readonly string[] | undefined, options: vscode.AuthenticationProviderSessionOptions): Promise<vscode.AuthenticationSession[]> {
104+
return Array.from(liveSessions.values())
105+
},
106+
async createSession(scopes: readonly string[], options: vscode.AuthenticationProviderSessionOptions): Promise<vscode.AuthenticationSession> {
107+
const realLogin = `Log in to ${DIAGNOSTIC_SOURCE_STR}`
108+
const publicLogin = `Use public token for ${DIAGNOSTIC_SOURCE_STR}`
109+
const res = await vscode.window.showQuickPick([
110+
realLogin,
111+
publicLogin,
112+
])
113+
if (!res) {
114+
throw new Error(`Cancelled creation of session for ${DIAGNOSTIC_SOURCE_STR}`)
115+
}
116+
let apiKey: string
117+
if (res === publicLogin) {
118+
apiKey = ''
119+
} else {
120+
let keyInfo: string
121+
let maybeApiKey = await vscode.window.showInputBox({
122+
title: 'Socket Security API Token',
123+
placeHolder: 'Leave this blank to use public demo token',
124+
prompt: 'Enter your API token from https://socket.dev/',
125+
async validateInput (value) {
126+
if (!value) return
127+
keyInfo = (await getQuota(value))!
128+
if (!keyInfo) return 'Unable to validate API key'
129+
}
130+
})
131+
// cancelled
132+
if (maybeApiKey === undefined) {
133+
throw new Error(`Cancelled creation of session for ${DIAGNOSTIC_SOURCE_STR}`)
134+
}
135+
apiKey = maybeApiKey
136+
}
137+
if (apiKey === '') {
138+
apiKey = PUBLIC_TOKEN
139+
}
140+
const session = {
141+
accessToken: apiKey,
142+
id: apiKey,
143+
account: {
144+
id: apiKey,
145+
label: `API Key for ${DIAGNOSTIC_SOURCE_STR}`
146+
},
147+
scopes: [],
148+
}
149+
let oldSessions = Array.from(liveSessions.values())
150+
liveSessions = new Map([
151+
[apiKey, session]
152+
])
153+
emitter.fire({
154+
added: [session],
155+
changed: [],
156+
removed: oldSessions
157+
})
158+
await syncLiveSessionsToDisk()
159+
return session
160+
},
161+
async removeSession(sessionId: string): Promise<void> {
162+
const session = liveSessions.get(sessionId)
163+
if (session) {
164+
emitter.fire({
165+
added: [],
166+
changed: [],
167+
removed: [session]
168+
})
169+
await syncLiveSessionsToDisk()
170+
}
171+
}
172+
})
173+
context.subscriptions.push(service)
174+
vscode.commands.registerCommand(`${EXTENSION_PREFIX}.login`, () => {
175+
vscode.authentication.getSession(`${EXTENSION_PREFIX}`, [], {
176+
createIfNone: true,
177+
})
178+
})
179+
//#endregion
180+
return {
181+
182+
}
183+
}

src/data/github.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ export async function sniffForGithubOrgOrUser(workspaceRootURI: vscode.Uri): Pro
7878
} catch (e) {}
7979
}
8080

81-
export function installGithubApp(uri: vscode.Uri) {
81+
export function installGithubApp(uri: vscode.Uri) {return
8282
vscode.authentication.getSession('github', [
8383
'read:user',
8484
'read:org'

src/data/go/executable.ts

Lines changed: 33 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -14,27 +14,47 @@ export async function initGo(): Promise<vscode.Disposable> {
1414

1515
const warned = new Set<string>();
1616

17-
export async function getGoExecutable(fileName?: string): Promise<string | void> {
17+
export async function getGoExecutable(fileName?: string): Promise<{execPath: string} | void> {
1818
// no executable in virtual workspace
1919
if (vscode.workspace.workspaceFolders?.every(f => f.uri.scheme !== 'file')) return
20+
let execPath: string = 'go';
21+
let usingSystemPath = true
2022
const workspaceConfig = vscode.workspace.getConfiguration(EXTENSION_PREFIX);
2123
const pathOverride = workspaceConfig.get<string>('goExecutable');
2224
if (pathOverride) {
23-
return Promise.resolve(vscode.workspace.fs.stat(vscode.Uri.file(pathOverride))).then(
24-
st => {
25-
if (st.type & vscode.FileType.File) return pathOverride;
25+
try {
26+
const st = await vscode.workspace.fs.stat(vscode.Uri.file(pathOverride))
27+
if (st.type & vscode.FileType.File) {
28+
usingSystemPath = false;
29+
execPath = pathOverride;
30+
} else {
2631
throw new Error('not a file')
2732
}
28-
).catch(err => {
29-
vscode.window.showErrorMessage(`Failed to find Go binary at '${pathOverride}'. Please update ${EXTENSION_PREFIX}.goExecutable.`)
30-
})
33+
} catch {
34+
}
35+
if (usingSystemPath) {
36+
vscode.window.showErrorMessage(`Failed to find Go binary at '${pathOverride}'. Please update ${EXTENSION_PREFIX}.pythonInterpreter.`);
37+
}
38+
}
39+
if (usingSystemPath) {
40+
const ext = await getGoExtension();
41+
const cmd = await ext?.settings.getExecutionCommand(
42+
'go',
43+
fileName && vscode.Uri.file(fileName)
44+
)
45+
if (cmd) {
46+
usingSystemPath = false;
47+
execPath = cmd.binPath
48+
} else {
49+
// TODO: make this less noisy
50+
// warnToInstallMoreReliableGo(ext);
51+
}
3152
}
32-
const ext = await getGoExtension();
33-
const cmd = await ext?.settings.getExecutionCommand(
34-
'go',
35-
fileName && vscode.Uri.file(fileName)
36-
)
37-
if (cmd) return cmd.binPath
53+
return {execPath}
54+
}
55+
56+
function warnToInstallMoreReliableGo(ext: vscode.Extension<any>) {
57+
const workspaceConfig = vscode.workspace.getConfiguration(EXTENSION_PREFIX);
3858
const workspaceID = vscode.workspace.name ||
3959
vscode.workspace.workspaceFolders?.map(f => f.uri.fsPath).join(',') ||
4060
vscode.window.activeTextEditor?.document.uri.fsPath;

0 commit comments

Comments
 (0)