Skip to content

Commit 4553e71

Browse files
authored
handle invalid session (#556)
* handle invalid session * yarn lock cleanup * move last time notified to session authenticate
1 parent d684ff5 commit 4553e71

24 files changed

+1288
-112
lines changed

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,3 +3,5 @@ node_modules
33
.DS_Store
44
lib/Constants.ts.local
55
dist/
6+
.env.local
7+
.vscode-test/**

.vscode-test.mjs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
import { defineConfig } from '@vscode/test-cli';
2+
3+
export default defineConfig({
4+
files: 'dist/test/**/*.test.js',
5+
});

.vscode/launch.json

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -44,10 +44,10 @@
4444
"runtimeExecutable": "${execPath}",
4545
"args": [
4646
"--extensionDevelopmentPath=${workspaceFolder}",
47-
"--extensionTestsPath=${workspaceFolder}/out/test"
47+
"--extensionTestsPath=${workspaceFolder}/dist/test/suite/index"
4848
],
4949
"outFiles": [
50-
"${workspaceFolder}/out/test/**/*.js"
50+
"${workspaceFolder}/dist/test/**/*.js"
5151
],
5252
"preLaunchTask": "npm: test-compile"
5353
}
@@ -57,8 +57,8 @@
5757
"name": "Multiple Extensions",
5858
// Launch 2 debugger extensions at once
5959
"configurations": [
60-
"Launch Extension",
61-
"Launch Extension"
60+
"Launch Extension Prod",
61+
"Launch Extension Prod"
6262
]
6363
}
6464
]

.vscodeignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ typings/**
33
test/**
44
**/*.ts
55
**/*.map
6+
**/*.js.map
67
.gitignore
78
.github/**
89
*.vsix

package.json

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "swdc-vscode",
33
"displayName": "Code Time",
4-
"version": "2.8.9",
4+
"version": "2.8.11",
55
"publisher": "softwaredotcom",
66
"description": "Code Time is an open source plugin that provides programming metrics right in Visual Studio Code.",
77
"author": {
@@ -52,7 +52,8 @@
5252
"watch:extension": "tsc -watch -p ./",
5353
"watch:views": "webpack --watch --mode development",
5454
"vscode:prepublish": "webpack --mode production",
55-
"test-compile": "tsc -p ./"
55+
"test-compile": "tsc -p ./",
56+
"test": "tsc -p ./ & vscode-test"
5657
},
5758
"contributes": {
5859
"commands": [
@@ -133,7 +134,13 @@
133134
"ts-loader": "^9.2.6",
134135
"typescript": "^5.4.5",
135136
"webpack": "^5.94.0",
136-
"webpack-cli": "^4.10.0"
137+
"webpack-cli": "^4.10.0",
138+
"@vscode/test-cli": "^0.0.11",
139+
"@vscode/test-electron": "^2.5.2",
140+
"mocha": "^11.7.1",
141+
"@types/sinon": "^17.0.4",
142+
"sinon": "^21.0.0",
143+
"dotenv": "^17.2.0"
137144
},
138145
"dependencies": {
139146
"@swdotcom/editor-flow": "1.1.3",

src/DataController.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@ export async function authenticationCompleteHandler(user: any, override_jwt: any
7777
if (authProvider) {
7878
authProvider.updateSession(getItem('jwt'), user);
7979
}
80+
setItem('lastTimeInvalidSessionNotified', 0);
8081
// update the login status
8182
showInformationMessage('Successfully logged on to Code Time');
8283

src/auth/AuthProvider.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
import {
22
authentication, AuthenticationProvider, AuthenticationProviderAuthenticationSessionsChangeEvent,
3-
AuthenticationSession, Disposable, Event, env, EventEmitter, ExtensionContext, ProgressLocation,
4-
Uri, UriHandler, window
3+
Disposable, Event, env, EventEmitter, ExtensionContext, ProgressLocation,
4+
Uri, UriHandler, window,
5+
AuthenticationSession
56
} from "vscode";
67
import { v4 as uuid } from 'uuid';
78
import { app_url } from "../Constants";

src/command-helper.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,6 @@ export function createCommands(
6161
cmds.push(
6262
commands.registerCommand('codetime.toggleStatusBar', () => {
6363
toggleStatusBar();
64-
commands.executeCommand('codetime.refreshCodeTimeView');
6564
})
6665
);
6766

src/extension.ts

Lines changed: 11 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -78,19 +78,18 @@ export async function activate(ctx: ExtensionContext) {
7878
// session: {id: <String>, accessToken: <String>, account: {label: <String>, id: <Number>}, scopes: [<String>,...]}
7979
const session = await authentication.getSession(AUTH_TYPE, [], { createIfNone: false });
8080
let jwt = getItem('jwt');
81-
user = await getUser();
82-
if (session) {
83-
// fetch the user with the non-session jwt to compare
84-
if (!user || user.email != session.account.label) {
85-
jwt = session.accessToken;
86-
// update the local storage with the new user
87-
setItem('name', session.account.label);
88-
setItem('jwt', jwt);
89-
user = await getUser(jwt);
81+
if (session?.accessToken) {
82+
jwt = session.accessToken;
83+
// update local storage with the session information
84+
setItem('name', session.account.label);
85+
setItem('jwt', jwt);
86+
// cache the user based on the session jwt
87+
await getUser(jwt);
88+
} else if (jwt) {
89+
const user = await getUser(jwt);
90+
if (user?.registered) {
91+
authProvider.updateSession(jwt, user);
9092
}
91-
} else if (jwt && user?.registered) {
92-
// update the session with the existing jwt
93-
authProvider.updateSession(jwt, user);
9493
}
9594

9695
if (jwt) {

src/http/HttpClient.ts

Lines changed: 36 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import axios from 'axios';
2-
import { version, window } from 'vscode';
3-
import { app_url } from '../Constants';
2+
import { commands, version, window } from 'vscode';
3+
import { app_url, ONE_MIN_MILLIS } from '../Constants';
44
import {
55
logIt,
66
getPluginId,
@@ -9,7 +9,8 @@ import {
99
getOs,
1010
getPluginUuid,
1111
getItem,
12-
setItem
12+
setItem,
13+
isPrimaryWindow
1314
} from '../Util';
1415

1516
// build the axios client
@@ -28,6 +29,8 @@ const appApi: any = axios.create({
2829
}
2930
});
3031

32+
let invalidSessionNotified: boolean = false;
33+
3134
// Evaluate these headers on every request since these values can change
3235
async function dynamicHeaders(override_token?: string) {
3336
let headers: any = {
@@ -50,11 +53,25 @@ async function dynamicHeaders(override_token?: string) {
5053
}
5154

5255
export async function appGet(api: string, queryParams: any = {}, token_override: any = '') {
53-
return await appApi.get(api, { params: queryParams, headers: await dynamicHeaders(token_override) }).catch((err: any) => {
56+
const headers = await dynamicHeaders(token_override);
57+
if (!headers['Authorization'] && isPrimaryWindow()) {
58+
const currentTime = Date.now();
59+
const lastTimeInvalidSessionNotified = Number(getItem('lastTimeInvalidSessionNotified') || 0);
60+
if (!invalidSessionNotified && (currentTime - lastTimeInvalidSessionNotified > ONE_MIN_MILLIS * 60 * 24)) {
61+
logIt(`No authorization token found for GET ${api}. Please ensure you are logged in.`);
62+
invalidSessionNotified = true;
63+
setItem('lastTimeInvalidSessionNotified', currentTime);
64+
await invalidSessionPrompt();
65+
}
66+
return;
67+
}
68+
return await appApi.get(api, { params: queryParams, headers: headers }).then((resp: any) => {
69+
return resp;
70+
}).catch((err: any) => {
5471
logIt(`error for GET ${api}, message: ${err.message}`);
5572
if (getResponseStatus(err?.response) === 401) {
5673
// clear the JWT because it is invalid
57-
setItem('jwt', null)
74+
setItem('jwt', null);
5875
}
5976
return err;
6077
});
@@ -103,7 +120,7 @@ export function isResponseOk(resp: any) {
103120
return false;
104121
}
105122

106-
function getResponseStatus(resp: any) {
123+
export function getResponseStatus(resp: any) {
107124
let status = null;
108125
if (resp?.status) {
109126
status = resp.status;
@@ -113,10 +130,23 @@ function getResponseStatus(resp: any) {
113130
status = 500;
114131
} else if (resp?.code === 'ECONNREFUSED') {
115132
status = 503;
133+
} else if (resp?.code === 'ENOTFOUND') {
134+
status = 404;
116135
}
117136
return status;
118137
}
119138

139+
async function invalidSessionPrompt() {
140+
const selection = await window.showInformationMessage(
141+
"We couldn't verify your session. Please log in again to continue using Code Time features",
142+
{ modal: true },
143+
...['Login']
144+
);
145+
if (selection === 'Login') {
146+
commands.executeCommand('codetime.login');
147+
}
148+
}
149+
120150
async function getAuthorization() {
121151
const token = getItem('jwt');
122152

0 commit comments

Comments
 (0)