Skip to content

Commit 609c78a

Browse files
committed
fix problem if bad internet stops getting globs and fix bug where cant login
1 parent 355f32a commit 609c78a

6 files changed

Lines changed: 126 additions & 93 deletions

File tree

src/data/glob-patterns.ts

Lines changed: 24 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,27 @@
1-
import { IncomingMessage } from 'node:http';
2-
import * as https from 'node:https';
3-
import { once } from 'node:stream';
4-
import { text } from 'stream/consumers';
1+
import { IncomingMessage } from 'node:http'
2+
import * as https from 'node:https'
3+
import { once } from 'node:stream'
4+
import { text } from 'stream/consumers'
55
import { flattenGlob } from '../util'
66

77
export type GlobPatterns = Record<string, Record<string, { pattern: string }>>
88

9-
let globPatternsPromise: Promise<GlobPatterns> | undefined;
9+
let globPatternsPromise: Promise<GlobPatterns> | undefined
1010

1111
const replaceCasedChars = (chars: string) =>
1212
chars.replace(/[a-zA-Z]/g, c => `[${c.toLowerCase()}${c.toUpperCase()}]`)
1313

1414
// TODO: can VSCode do case insensitive match without this?
1515
function caseDesensitize(pattern: string) {
16-
let out = '';
16+
let out = ''
1717
const charGroup = /\[[^\]]+?\]/g
18-
let lastIndex = 0;
18+
let lastIndex = 0
1919
for (let match: RegExpExecArray | null = null; match = charGroup.exec(pattern);) {
20-
out += replaceCasedChars(pattern.slice(lastIndex, match.index)) + match[0];
21-
lastIndex = match.index + match[0].length;
20+
out += replaceCasedChars(pattern.slice(lastIndex, match.index)) + match[0]
21+
lastIndex = match.index + match[0].length
2222
}
23-
out += replaceCasedChars(pattern.slice(lastIndex));
24-
return out;
23+
out += replaceCasedChars(pattern.slice(lastIndex))
24+
return out
2525
}
2626

2727
export async function getGlobPatterns() {
@@ -36,7 +36,7 @@ export async function getGlobPatterns() {
3636
}
3737
for (const eco in result) {
3838
for (const name in result[eco]) {
39-
const target = result[eco][name];
39+
const target = result[eco][name]
4040
target.pattern = caseDesensitize(flattenGlob(target.pattern))
4141
}
4242
}
@@ -45,7 +45,18 @@ export async function getGlobPatterns() {
4545
catch(err => {
4646
// allow retry
4747
globPatternsPromise = undefined
48-
throw err
48+
// snapshot of supported patterns
49+
return {
50+
"cdx": { "json": { "pattern": "{bom,c{yclone,}dx[-.]*,*[-.]c{yclone,}dx}.json" }, "xml": { "pattern": "{bom,c{yclone,}dx[-.]*,*[-.]c{yclone,}dx}.xml" } },
51+
"gem": { "gemfileLock": { "pattern": "Gemfile.lock" } },
52+
"golang": { "gomod": { "pattern": "go.mod" }, "gosum": { "pattern": "go.sum" } },
53+
"maven": { "buildr": { "pattern": "Buildfile" }, "gradle": { "pattern": "{*.,}gradle{.lockfile,}" }, "ivy": { "pattern": "ivy.xml" }, "kotlin": { "pattern": "*.gradle.kts" }, "leiningen": { "pattern": "project.clj" }, "pomxml": { "pattern": "{*-*.,}pom{.xml,}" }, "sbt": { "pattern": "build.sbt" } },
54+
"npm": { "npmshrinkwrap": { "pattern": "npm-shrinkwrap.json" }, "packagejson": { "pattern": "package.json" }, "packagelockjson": { "pattern": "package-lock.json" }, "pnpmlock": { "pattern": "pnpm-lock.y{a,}ml" }, "pnpmworkspace": { "pattern": "pnpm-workspace.y{a,}ml" }, "yarnlock": { "pattern": "yarn.lock" } },
55+
"pypi": { "cdx-json": { "pattern": "{bom,c{yclone,}dx[-.]*,*[-.]c{yclone,}dx}.json" }, "cdx-xml": { "pattern": "{bom,c{yclone,}dx[-.]*,*[-.]c{yclone,}dx}.xml" }, "pipfile": { "pattern": "pipfile" }, "piplock": { "pattern": "pipfile.lock" }, "pkginfo": { "pattern": "{PKG-INFO,METADATA}" }, "poetry": { "pattern": "poetry.lock" }, "pylock": { "pattern": "pylock{,.*}.toml" }, "pyproject": { "pattern": "pyproject.toml" }, "requirements": { "pattern": "{*requirements{.frozen,{[-_]*,}.txt},requirements/*.txt}" }, "setuppy": { "pattern": "setup.py" }, "spdx-json": { "pattern": "*[-.]spdx.json" }, "uvlock": { "pattern": "uv.lock" } }, "spdx": { "json": { "pattern": "*[-.]spdx.json" } },
56+
"nuget": { "visualStudioSolution": { "pattern": "*.sln" }, "msbuildProject": { "pattern": "*.*proj" }, "targets": { "pattern": "*.targets" }, "props": { "pattern": "*.props" }, "msbuildProjectItems": { "pattern": "*.projitems" }, "nuspec": { "pattern": "*.nuspec" }, "packageConfig": { "pattern": "{packages.*.config,packages.config}" }, "packagesLock": { "pattern": "packages.lock.json" } },
57+
"socket": { "facts": { "pattern": ".socket.facts.json" } },
58+
"cargo": { "cargoToml": { "pattern": "Cargo.toml" }, "cargoLock": { "pattern": "Cargo.lock" } }
59+
}
4960
})
5061
}
5162
return globPatternsPromise

src/data/socket-api-config.ts

Lines changed: 84 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,15 @@ import { IncomingMessage } from 'node:http'
77
import { text } from 'node:stream/consumers'
88
import constants from '@socketsecurity/registry/lib/constants'
99
import { addDisposablesTo } from '../util'
10+
import { log } from 'node:console'
1011

1112
const { SOCKET_PUBLIC_API_TOKEN } = constants
1213

1314
export type APIConfig = {
1415
apiKey: string
1516
}
1617

17-
let apiConf: APIConfig | {} | undefined
18+
let apiConf: APIConfig | undefined
1819

1920
let dataHome = process.platform === 'win32'
2021
? process.env['LOCALAPPDATA']
@@ -97,18 +98,19 @@ async function loadConfig(update?: boolean) {
9798

9899
async function findAPIConfig() {
99100
if (!apiConf) {
100-
apiConf = {}
101+
apiConf = undefined
101102
let keyInfo: OrganizationsRecord | null
102103
const envKey = process.env.SOCKET_SECURITY_API_TOKEN ?? process.env.SOCKET_SECURITY_API_KEY
103104
if (envKey) {
104105
keyInfo = await getOrganizations(envKey)
105-
if (keyInfo) {
106-
apiConf = getConfigFromSettings(envKey)
106+
apiConf = {
107+
apiKey: envKey
107108
}
109+
} else {
110+
await loadConfig()
108111
}
109-
if (!(apiConf as APIConfig).apiKey) await loadConfig()
110112
}
111-
return (apiConf as APIConfig).apiKey ? apiConf as APIConfig : null
113+
return (apiConf as APIConfig)?.apiKey ? apiConf as APIConfig : null
112114
}
113115

114116
let existingFindCall: Promise<APIConfig | null> | null = null
@@ -121,64 +123,87 @@ export async function getExistingAPIConfig() {
121123
return result
122124
}
123125

124-
export async function usePublicConfig(force?: boolean) {
125-
if (force || !getExistingAPIConfig()) {
126-
const apiKey = SOCKET_PUBLIC_API_TOKEN
127-
await saveConfig(apiKey, [])
128-
changeAPIConf.fire()
129-
}
130-
return apiConf as APIConfig
131-
}
132-
133-
export async function getAPIConfig(force?: boolean) {
134-
if (!force) {
135-
const existingConf = await getExistingAPIConfig()
136-
if (existingConf) return existingConf
126+
let pendingNewConfig: Promise<APIConfig | null> | null = null
127+
export async function getAPIConfig() {
128+
const existingConf = await getExistingAPIConfig()
129+
if (existingConf) {
130+
return existingConf
137131
}
138-
let organizations: OrganizationsRecord
139-
let apiKey = await vscode.window.showInputBox({
140-
title: 'Socket Security API Token',
141-
placeHolder: 'Leave this blank to use a public token',
142-
prompt: 'Enter your API token from https://socket.dev/',
143-
async validateInput(value) {
144-
if (!value) return
145-
organizations = (await getOrganizations(value))!
146-
if (!organizations) return 'Invalid API key'
147-
}
148-
})
149-
if (apiKey === undefined) {
150-
return null
132+
if (pendingNewConfig) {
133+
return pendingNewConfig
151134
}
152-
let enforcedOrgs: string[] = []
153-
if (!apiKey) {
154-
apiKey = SOCKET_PUBLIC_API_TOKEN
155-
organizations = (await getOrganizations(apiKey))!
156-
} else {
157-
let organizationsList = Object.values(organizations!.organizations!)
158-
if (organizationsList.length) {
159-
(organizationsList[0] as OrgInfo)
160-
const options: (vscode.QuickPickItem & { id: string | null })[] = [
161-
...organizationsList.map(org => {
162-
return {
163-
label: org.name,
164-
id: org.id,
135+
async function getNewConfig() {
136+
let organizations: OrganizationsRecord
137+
let apiKey = null
138+
while (true) {
139+
const loginChoice = await vscode.window.showInformationMessage('Socket Security requires authentication for full functionality.',
140+
'Authenticate',
141+
'Stay logged out'
142+
)
143+
// they chose to ignore the prompt or opted to be logged out
144+
// it will come back later
145+
if (loginChoice === 'Stay logged out' || !loginChoice) {
146+
break
147+
}
148+
if (loginChoice === 'Authenticate') {
149+
apiKey = await vscode.window.showInputBox({
150+
title: 'Socket Security API Token',
151+
placeHolder: 'Leave this blank to stay logged out',
152+
prompt: 'Enter your API token from https://socket.dev/',
153+
async validateInput(value) {
154+
if (!value) return
155+
organizations = (await getOrganizations(value))!
156+
if (!organizations) return 'Invalid API key'
165157
}
166-
}),
167-
{
168-
label: 'None',
169-
id: null
158+
})
159+
// vscode gives undefined if focus is lost, this is error prone UX
160+
// show the informative message again that they can ignore
161+
// only consider the user to have made a choice if they enter a value
162+
if (typeof apiKey === 'string') {
163+
break
170164
}
171-
]
172-
const result = await vscode.window.showQuickPick(options, {
173-
title: 'Which organization\'s policies should Socket enforce system-wide?'
174-
})
175-
if (result?.id) enforcedOrgs = [result.id]
165+
}
176166
}
167+
let enforcedOrgs: string[] = []
168+
if (!apiKey || apiKey === SOCKET_PUBLIC_API_TOKEN) {
169+
// dont save to disk and don't ask for orgs
170+
apiConf = {
171+
apiKey: SOCKET_PUBLIC_API_TOKEN
172+
}
173+
changeAPIConf.fire()
174+
return apiConf
175+
} else {
176+
let organizationsList = Object.values(organizations!.organizations!)
177+
if (organizationsList.length) {
178+
(organizationsList[0] as OrgInfo)
179+
const options: (vscode.QuickPickItem & { id: string | null })[] = [
180+
...organizationsList.map(org => {
181+
return {
182+
label: org.name,
183+
id: org.id,
184+
}
185+
}),
186+
{
187+
label: 'None',
188+
id: null
189+
}
190+
]
191+
const result = await vscode.window.showQuickPick(options, {
192+
title: 'Which organization\'s policies should Socket enforce system-wide?'
193+
})
194+
if (result?.id) enforcedOrgs = [result.id]
195+
}
196+
}
197+
await saveConfig(apiKey, enforcedOrgs)
198+
apiConf = getConfigFromSettings(apiKey)
199+
changeAPIConf.fire()
200+
return apiConf
177201
}
178-
await saveConfig(apiKey, enforcedOrgs)
179-
apiConf = getConfigFromSettings(apiKey)
180-
changeAPIConf.fire()
181-
return apiConf as APIConfig
202+
pendingNewConfig = getNewConfig()
203+
pendingNewConfig.finally(() => {
204+
pendingNewConfig = null
205+
})
206+
return pendingNewConfig
182207
}
183208

184209
export function init(disposables?: vscode.Disposable[]) {
@@ -194,7 +219,7 @@ export function init(disposables?: vscode.Disposable[]) {
194219
watcher.onDidChange(() => loadConfig(true)),
195220
watcher.onDidCreate(() => loadConfig(true)),
196221
watcher.onDidDelete(() => {
197-
apiConf = {}
222+
apiConf = undefined
198223
})
199224
)
200225
}

src/infra/log.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,6 @@ const logger = vscode.window.createOutputChannel('Socket Security', {
44
log: true
55
})
66

7-
logger.appendLine('Socket Security extension started')
7+
logger.info('Socket Security extension started')
88

99
export default logger;

src/ui/decorations.ts

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ import { PURLPackageData } from './purl-alerts-and-scores/manager';
88
import { SUPPORTED_LSP_LANGUAGE_IDS_TO_PARSER } from './languages';
99
import { isPythonBuiltin } from '../data/python/interpreter';
1010
import * as Module from 'module';
11-
import { log } from 'console'
1211
import { getGlobPatterns } from '../data/glob-patterns'
1312

1413
export async function activate(context: vscode.ExtensionContext) {
@@ -50,7 +49,7 @@ class DecorationTypes {
5049
height: '12px',
5150
},
5251
});
53-
logger.info('Created error decoration', this.errorDecoration.key);
52+
// logger.debug('Created error decoration', this.errorDecoration.key);
5453
this.warningDecoration = vscode.window.createTextEditorDecorationType({
5554
isWholeLine: true,
5655
after: {
@@ -60,11 +59,11 @@ class DecorationTypes {
6059
height: '12px',
6160
},
6261
});
63-
logger.info('Created warning decoration', this.warningDecoration.key);
62+
// logger.debug('Created warning decoration', this.warningDecoration.key);
6463
this.informativeDecoration = vscode.window.createTextEditorDecorationType({
6564
isWholeLine: true
6665
});
67-
logger.info('Created informative decoration', this.informativeDecoration.key);
66+
// logger.debug('Created informative decoration', this.informativeDecoration.key);
6867
}
6968
}
7069

@@ -383,8 +382,8 @@ class DecorationManagerForDocument {
383382
const thisDocUpdateSignal = this.currentDocUpdate.signal;
384383
const externals = await parseExternals(doc);
385384
if (!externals) return;
386-
logger.info(`Parsed externals for ${docURI}:`, externals.size, 'externals found, aborted:', thisDocUpdateSignal.aborted);
387-
logger.info([...externals.keys()].join(', '));
385+
logger.debug(`Parsed externals for ${docURI}:`, externals.size, 'externals found, aborted:', thisDocUpdateSignal.aborted);
386+
logger.debug([...externals.keys()].join(', '));
388387
if (thisDocUpdateSignal.aborted) {
389388
console.info(`Decoration update for ${docURI} was aborted (parsing externals took longer than next update), skipping.`);
390389
return;
@@ -454,16 +453,16 @@ class DecorationManagerForDocument {
454453
async #decorateEverything(thisDecorationUpdateSignal = this.currentDocUpdate.signal) {
455454
if (!this.isDirty) return;
456455
let pending = [];
457-
logger.info(`Updating decorations for ${this.docURI} with externals:`, this.externalRefs.size, 'externals found');
456+
logger.debug(`Updating decorations for ${this.docURI} with externals:`, this.externalRefs.size, 'externals found');
458457
for (const editor of vscode.window.visibleTextEditors) {
459458
const editorURI = editor.document.uri.toString() as TextDocumentURIString;
460459
if (editorURI === this.docURI) {
461-
logger.info(`Matching editor ${editorURI} for decoration update`);
460+
logger.debug(`Matching editor ${editorURI} for decoration update`);
462461
pending.push(editor)
463462
}
464463
}
465464
if (pending.length === 0) {
466-
logger.info(`No editors found for ${this.docURI}, skipping decoration update`);
465+
logger.debug(`No editors found for ${this.docURI}, skipping decoration update`);
467466
return;
468467
}
469468
this.createDecorations();

src/ui/file.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,6 @@ import {activate as activateDecorations} from './decorations'
55
export function activate(
66
context: vscode.ExtensionContext,
77
) {
8-
logger.appendLine('Socket Security extension started decorating files')
8+
logger.debug('Socket Security extension started decorating files')
99
activateDecorations(context);
1010
}

0 commit comments

Comments
 (0)