Refresh dashboard authentication on every API call and every 15 minutes

This commit is contained in:
Dragory 2021-05-22 21:15:13 +03:00
parent 553fb57c46
commit f3a90faaa7
No known key found for this signature in database
GPG key ID: 5F387BA66DF8AAC1
4 changed files with 63 additions and 5 deletions

View file

@ -86,6 +86,7 @@ export function initAuth(app: express.Express) {
const userId = await apiLogins.getUserIdByApiKey(apiKey);
if (userId) {
void apiLogins.refreshApiKeyExpiryTime(apiKey); // Refresh expiry time in the background
return cb(null, { apiKey, userId });
}
@ -154,6 +155,12 @@ export function initAuth(app: express.Express) {
await apiLogins.expireApiKey(req.user!.apiKey);
return ok(res);
});
// API route to refresh the given API token's expiry time
// The actual refreshing happens in the api-token passport strategy above, so we just return 200 OK here
app.post("/auth/refresh", ...apiTokenAuthHandlers(), (req, res) => {
return ok(res);
});
}
export function apiTokenAuthHandlers() {

View file

@ -5,7 +5,9 @@ import crypto from "crypto";
import moment from "moment-timezone";
// tslint:disable-next-line:no-submodule-imports
import uuidv4 from "uuid/v4";
import { DBDateFormat } from "../utils";
import { DAYS, DBDateFormat } from "../utils";
const LOGIN_EXPIRY_TIME = 1 * DAYS;
export class ApiLogins extends BaseRepository {
private apiLogins: Repository<ApiLogin>;
@ -68,7 +70,7 @@ export class ApiLogins extends BaseRepository {
logged_in_at: moment.utc().format(DBDateFormat),
expires_at: moment
.utc()
.add(1, "day")
.add(LOGIN_EXPIRY_TIME, "ms")
.format(DBDateFormat),
});
@ -86,4 +88,19 @@ export class ApiLogins extends BaseRepository {
},
);
}
async refreshApiKeyExpiryTime(apiKey) {
const [loginId, token] = apiKey.split(".");
if (!loginId || !token) return;
await this.apiLogins.update(
{ id: loginId },
{
expires_at: moment()
.utc()
.add(LOGIN_EXPIRY_TIME, "ms")
.format(DBDateFormat),
},
);
}
}

View file

@ -1,6 +1,9 @@
import { get, post } from "../api";
import { ActionTree, Module } from "vuex";
import { AuthState, RootState } from "./types";
import { AuthState, IntervalType, RootState } from "./types";
// Refresh auth every 15 minutes
const AUTH_REFRESH_INTERVAL = 1000 * 60 * 15;
export const AuthStore: Module<AuthState, RootState> = {
namespaced: true,
@ -8,6 +11,7 @@ export const AuthStore: Module<AuthState, RootState> = {
state: {
apiKey: null,
loadedInitialAuth: false,
authRefreshInterval: null,
},
actions: {
@ -31,12 +35,34 @@ export const AuthStore: Module<AuthState, RootState> = {
commit("markInitialAuthLoaded");
},
setApiKey({ commit, state }, newKey: string) {
setApiKey({ commit, state, dispatch }, newKey: string) {
localStorage.setItem("apiKey", newKey);
commit("setApiKey", newKey);
dispatch("startAuthAutoRefresh");
},
clearApiKey({ commit }) {
async startAuthAutoRefresh({ commit, state, dispatch }) {
// End a previously active auto-refresh, if any
await dispatch("endAuthAutoRefresh");
// Start new auto-refresh
const refreshInterval = setInterval(async () => {
await post("auth/refresh", { key: state.apiKey });
}, AUTH_REFRESH_INTERVAL);
commit("setAuthRefreshInterval", refreshInterval);
},
endAuthAutoRefresh({ commit, state }) {
if (state.authRefreshInterval) {
window.clearInterval(state.authRefreshInterval);
}
commit("setAuthRefreshInterval", null);
},
async clearApiKey({ commit, dispatch }) {
await dispatch("endAuthAutoRefresh");
localStorage.removeItem("apiKey");
commit("setApiKey", null);
},
@ -52,6 +78,10 @@ export const AuthStore: Module<AuthState, RootState> = {
state.apiKey = key;
},
setAuthRefreshInterval(state: AuthState, interval: IntervalType | null) {
state.authRefreshInterval = interval;
},
markInitialAuthLoaded(state: AuthState) {
state.loadedInitialAuth = true;
},

View file

@ -7,9 +7,13 @@ export enum LoadStatus {
Done,
}
export type TimeoutType = ReturnType<typeof setTimeout>;
export type IntervalType = ReturnType<typeof setInterval>;
export interface AuthState {
apiKey: string | null;
loadedInitialAuth: boolean;
authRefreshInterval: IntervalType | null;
}
export interface GuildState {