forked from openiap/opencore
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathAuth.ts
More file actions
115 lines (114 loc) · 4.91 KB
/
Copy pathAuth.ts
File metadata and controls
115 lines (114 loc) · 4.91 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
import { Crypt } from "./Crypt";
import { NoderedUtil, User } from "@openiap/openflow-api";
import { DBHelper } from "./DBHelper";
import { Span } from "@opentelemetry/api";
import { Logger } from "./Logger";
import { Config } from "./Config";
export class Auth {
public static async ValidateByPassword(username: string, password: string, parent: Span): Promise<User> {
const span: Span = Logger.otel.startSubSpan("Auth.ValidateByPassword", parent);
try {
if (username === null || username === undefined || username === "") { throw Error("Username cannot be null"); }
span.setAttribute("username", username);
if (password === null || password === undefined || password === "") { throw Error("Password cannot be null"); }
const user: User = await DBHelper.FindByUsername(username, null, span);
if (user === null || user === undefined) { return null; }
if ((await Crypt.compare(password, user.passwordhash, span)) !== true) { return null; }
return user;
} catch (error) {
span.recordException(error);
throw error;
} finally {
Logger.otel.endSpan(span);
}
}
public static authorizationCache: HashTable<CachedUser> = {};
private static cacheTimer: NodeJS.Timeout;
public static getUser(key: string, type: string): User {
if (NoderedUtil.IsNullUndefinded(this.cacheTimer)) this.cacheTimer = setInterval(this.cleanCache, 60000)
var res: CachedUser = this.authorizationCache[key + type];
if (res === null || res === undefined) return null;
var begin: number = res.firstsignin.getTime();
var end: number = new Date().getTime();
var seconds = Math.round((end - begin) / 1000);
let cache_seconds: number = Config.api_credential_cache_seconds;
if (type == "grafana") cache_seconds = Config.grafana_credential_cache_seconds;
if (type == "dashboard") cache_seconds = Config.dashboard_credential_cache_seconds;
if (type == "cleanacl") cache_seconds = Config.cleanacl_credential_cache_seconds;
if (seconds < cache_seconds) {
Logger.instanse.silly("Return user " + res.user.username + " from cache");
return res.user;
}
this.RemoveUser(key, type);
return null;
}
private static async cleanCache() {
try {
if (this.authorizationCache == null) return;
const keys: string[] = Object.keys(this.authorizationCache);
for (let i = keys.length - 1; i >= 0; i--) {
let key: string = keys[i];
var res: CachedUser = this.authorizationCache[key];
if (res === null || res === undefined) continue;
var begin: number = res.firstsignin.getTime();
var end: number = new Date().getTime();
var seconds = Math.round((end - begin) / 1000);
let cache_seconds: number = Config.api_credential_cache_seconds;
if (res.type == "grafana") cache_seconds = Config.grafana_credential_cache_seconds;
if (res.type == "dashboard") cache_seconds = Config.dashboard_credential_cache_seconds;
if (res.type == "cleanacl") cache_seconds = Config.cleanacl_credential_cache_seconds;
if (seconds >= cache_seconds) {
this.RemoveUser(key, res.type);
}
}
} catch (error) {
Logger.instanse.error(error)
}
}
public static async RemoveUser(key: string, type: string): Promise<void> {
await semaphore.down();
if (!NoderedUtil.IsNullUndefinded(this.authorizationCache[key + type])) {
Logger.instanse.silly("Delete user with key " + key + " from cache");
delete this.authorizationCache[key + type];
}
semaphore.up();
}
public static async AddUser(user: User, key: string, type: string): Promise<void> {
await semaphore.down();
if (NoderedUtil.IsNullUndefinded(this.authorizationCache[key + type])) {
Logger.instanse.silly("Adding user " + user.name + " to cache with key " + key);
var cuser: CachedUser = new CachedUser(user, user._id, type);
this.authorizationCache[key + type] = cuser;
}
semaphore.up();
}
}
export class CachedUser {
public firstsignin: Date;
constructor(
public user: User,
public _id: string,
public type: string
) {
this.firstsignin = new Date();
}
}
interface HashTable<T> {
[key: string]: T;
}
const Semaphore = (n) => ({
n,
async down() {
while (this.n <= 0) await this.wait();
this.n--;
},
up() {
this.n++;
},
async wait() {
if (this.n <= 0) return new Promise((res, req) => {
setImmediate(async () => res(await this.wait()))
});
},
});
const semaphore = Semaphore(1);