Skip to content

Commit 8425d31

Browse files
committed
Add more tests
1 parent a1dbd76 commit 8425d31

21 files changed

Lines changed: 487 additions & 100 deletions

OpenFlow/src/Audit.ts

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,11 @@ import { TokenUser, Base, Rights, NoderedUtil } from "@openiap/openflow-api";
33
import { Crypt } from "./Crypt";
44
import { Span } from "@opentelemetry/api";
55

6+
export type tokenType = "local" | "jwtsignin" | "samltoken" | "tokenissued" | "weblogin";
7+
export type loginProvider = "saml" | "google" | "local" | "websocket";
8+
export type clientType = "browser" | "openrpa" | "nodered" | "webapp" | "openflow" | "powershell" | "mobileapp" | "samlverify" | "googleverify" | "aiotmobileapp" | "aiotwebapp";
69
export class Audit {
7-
public static LoginSuccess(user: TokenUser, type: string, provider: string, remoteip: string, clientagent: string, clientversion: string, parent: Span) {
10+
public static LoginSuccess(user: TokenUser, type: tokenType, provider: loginProvider, remoteip: string, clientagent: clientType, clientversion: string, parent: Span) {
811
const log: Singin = new Singin();
912
Base.addRight(log, user._id, user.name, [Rights.read, Rights.update, Rights.invoke]);
1013
log.remoteip = remoteip;
@@ -19,7 +22,7 @@ export class Audit {
1922
Config.db.InsertOne(log, "audit", 0, false, Crypt.rootToken(), parent)
2023
.catch((error) => console.error("failed InsertOne in LoginSuccess: " + error));
2124
}
22-
public static ImpersonateSuccess(user: TokenUser, impostor: TokenUser, clientagent: string, clientversion: string, parent: Span) {
25+
public static ImpersonateSuccess(user: TokenUser, impostor: TokenUser, clientagent: clientType, clientversion: string, parent: Span) {
2326
const log: Singin = new Singin();
2427
Base.addRight(log, user._id, user.name, [Rights.read]);
2528
Base.addRight(log, impostor._id, impostor.name, [Rights.read]);
@@ -36,7 +39,7 @@ export class Audit {
3639
Config.db.InsertOne(log, "audit", 0, false, Crypt.rootToken(), parent)
3740
.catch((error) => console.error("failed InsertOne in ImpersonateSuccess: " + error));
3841
}
39-
public static ImpersonateFailed(user: TokenUser, impostor: TokenUser, clientagent: string, clientversion: string, parent: Span) {
42+
public static ImpersonateFailed(user: TokenUser, impostor: TokenUser, clientagent: clientType, clientversion: string, parent: Span) {
4043
const log: Singin = new Singin();
4144
Base.addRight(log, user._id, user.name, [Rights.read]);
4245
Base.addRight(log, impostor._id, impostor.name, [Rights.read]);
@@ -52,7 +55,7 @@ export class Audit {
5255
Config.db.InsertOne(log, "audit", 0, false, Crypt.rootToken(), parent)
5356
.catch((error) => console.error("failed InsertOne in ImpersonateFailed: " + error));
5457
}
55-
public static LoginFailed(username: string, type: string, provider: string, remoteip: string, clientagent: string, clientversion: string, parent: Span) {
58+
public static LoginFailed(username: string, type: tokenType, provider: loginProvider, remoteip: string, clientagent: clientType, clientversion: string, parent: Span) {
5659
const log: Singin = new Singin();
5760
log.remoteip = remoteip;
5861
log.success = false;

OpenFlow/src/Auth.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,11 @@ export class Auth {
2525

2626
public static authorizationCache: HashTable<CachedUser> = {};
2727
private static cacheTimer: NodeJS.Timeout;
28+
public static shutdown() {
29+
if (!NoderedUtil.IsNullUndefinded(this.cacheTimer)) {
30+
clearInterval(this.cacheTimer);
31+
}
32+
}
2833
public static getUser(key: string, type: string): User {
2934
if (NoderedUtil.IsNullUndefinded(this.cacheTimer)) this.cacheTimer = setInterval(this.cleanCache, 60000)
3035
var res: CachedUser = this.authorizationCache[key + type];
@@ -43,7 +48,7 @@ export class Auth {
4348
this.RemoveUser(key, type);
4449
return null;
4550
}
46-
private static async cleanCache() {
51+
public static async cleanCache() {
4752
try {
4853
if (this.authorizationCache == null) return;
4954
const keys: string[] = Object.keys(this.authorizationCache);

OpenFlow/src/Config.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@ export class Config {
1818
public static reload(): void {
1919
Config.getversion();
2020
Config.logpath = Config.getEnv("logpath", __dirname);
21+
Config.log_error_stack = Config.parseBoolean(Config.getEnv("log_error_stack", "false"));
22+
Config.log_errors = Config.parseBoolean(Config.getEnv("log_errors", "true"));
2123
Config.log_queries = Config.parseBoolean(Config.getEnv("log_queries", "false"));
2224
Config.log_aggregates = Config.parseBoolean(Config.getEnv("log_aggregates", "false"));
2325
Config.log_inserts = Config.parseBoolean(Config.getEnv("log_inserts", "false"));
@@ -157,6 +159,8 @@ export class Config {
157159
public static license_key: string = Config.getEnv("license_key", "");
158160
public static version: string = Config.getversion();
159161
public static logpath: string = Config.getEnv("logpath", __dirname);
162+
public static log_error_stack: boolean = Config.parseBoolean(Config.getEnv("log_error_stack", "false"));
163+
public static log_errors: boolean = Config.parseBoolean(Config.getEnv("log_errors", "true"));
160164
public static log_queries: boolean = Config.parseBoolean(Config.getEnv("log_queries", "false"));
161165
public static log_aggregates: boolean = Config.parseBoolean(Config.getEnv("log_aggregates", "false"));
162166
public static log_inserts: boolean = Config.parseBoolean(Config.getEnv("log_inserts", "false"));

OpenFlow/src/DBHelper.ts

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ export class DBHelper {
88
public static async FindByUsername(username: string, jwt: string, parent: Span): Promise<User> {
99
const span: Span = Logger.otel.startSubSpan("dbhelper.FindByUsername", parent);
1010
try {
11+
if (NoderedUtil.IsNullEmpty(username)) throw new Error("Username is mandatory")
1112
const byuser = { username: new RegExp(["^", username, "$"].join(""), "i") };
1213
const byid = { federationids: new RegExp(["^", username, "$"].join(""), "i") }
1314
const q = { $or: [byuser, byid] };
@@ -42,6 +43,7 @@ export class DBHelper {
4243
try {
4344
var _id = id;
4445
if (NoderedUtil.IsNullEmpty(_id)) _id = null;
46+
if (NoderedUtil.IsNullEmpty(username) && NoderedUtil.IsNullEmpty(_id)) throw new Error("Either username or id is mandatory");
4547
const items: User[] = await Config.db.query<User>({ $or: [{ username: new RegExp(["^", username, "$"].join(""), "i") }, { _id }] },
4648
null, 1, 0, null, "users", Crypt.rootToken(), undefined, undefined, span);
4749
if (items === null || items === undefined || items.length === 0) { return null; }
@@ -56,6 +58,7 @@ export class DBHelper {
5658
public static async FindByUsernameOrFederationid(username: string, parent: Span): Promise<User> {
5759
const span: Span = Logger.otel.startSubSpan("dbhelper.FindByUsernameOrFederationid", parent);
5860
try {
61+
if (NoderedUtil.IsNullEmpty(username)) throw new Error("username cannot be null");
5962
const byuser = { username: new RegExp(["^", username, "$"].join(""), "i") };
6063
const byid = { federationids: new RegExp(["^", username, "$"].join(""), "i") }
6164
const q = { $or: [byuser, byid] };
@@ -74,6 +77,7 @@ export class DBHelper {
7477
public static async DecorateWithRoles<T extends TokenUser | User>(user: T, parent: Span): Promise<T> {
7578
const span: Span = Logger.otel.startSubSpan("dbhelper.DecorateWithRoles", parent);
7679
try {
80+
if (NoderedUtil.IsNullUndefinded(user)) throw new Error("User is mandatory");
7781
if (!Config.decorate_roles_fetching_all_roles) {
7882
if (!user.roles) user.roles = [];
7983
const pipe: any = [{ "$match": { "_id": user._id } },
@@ -164,22 +168,18 @@ export class DBHelper {
164168
return user as any;
165169
}
166170
public static async FindRoleByName(name: string, parent: Span): Promise<Role> {
167-
const items: Role[] = await Config.db.query<Role>({ name: name }, null, 1, 0, null, "users", Crypt.rootToken(), undefined, undefined, parent);
171+
const items: Role[] = await Config.db.query<Role>({ name: name, "_type": "role" }, null, 1, 0, null, "users", Crypt.rootToken(), undefined, undefined, parent);
168172
if (items === null || items === undefined || items.length === 0) { return null; }
169173
return Role.assign(items[0]);
170174
}
171175
public static async FindRoleByNameOrId(name: string, id: string, parent: Span): Promise<Role> {
172-
try {
173-
var _id = id;
174-
if (NoderedUtil.IsNullEmpty(_id)) _id = null; // undefined is bad here
175-
const jwt = Crypt.rootToken();
176-
const items: Role[] = await Config.db.query<Role>({ $or: [{ name }, { _id }], "_type": "role" }, null, 5, 0, null, "users", jwt, undefined, undefined, parent);
177-
if (items === null || items === undefined || items.length === 0) { return null; }
178-
return Role.assign(items[0]);
179-
} catch (error) {
180-
console.error(error);
181-
return null;
182-
}
176+
var _id = id;
177+
if (NoderedUtil.IsNullEmpty(_id)) _id = null; // undefined is bad here
178+
if (NoderedUtil.IsNullEmpty(name) && NoderedUtil.IsNullEmpty(_id)) throw new Error("Either username or id is mandatory");
179+
const jwt = Crypt.rootToken();
180+
const items: Role[] = await Config.db.query<Role>({ $or: [{ name }, { _id }], "_type": "role" }, null, 5, 0, null, "users", jwt, undefined, undefined, parent);
181+
if (items === null || items === undefined || items.length === 0) { return null; }
182+
return Role.assign(items[0]);
183183
}
184184
public static async Save(item: User | Role, jwt: string, parent: Span): Promise<void> {
185185
await Config.db._UpdateOne(null, item, "users", 2, false, jwt, parent);
@@ -205,7 +205,7 @@ export class DBHelper {
205205
Logger.otel.endSpan(span);
206206
}
207207
}
208-
public static async ensureUser(jwt: string, name: string, username: string, id: string, password: string, parent: Span): Promise<User> {
208+
public static async EnsureUser(jwt: string, name: string, username: string, id: string, password: string, parent: Span): Promise<User> {
209209
const span: Span = Logger.otel.startSubSpan("dbhelper.ensureUser", parent);
210210
try {
211211
let user: User = await this.FindByUsernameOrId(username, id, span);

OpenFlow/src/DatabaseConnection.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -329,26 +329,26 @@ export class DatabaseConnection {
329329
} else if (arr[0]._type === "user") {
330330
let u: User = User.assign(arr[0]);
331331
if (!Base.hasRight(u, item._id, Rights.read)) {
332-
Logger.instanse.debug("Assigning " + item.name + " read permission to " + u.name);
332+
Logger.instanse.silly("Assigning " + item.name + " read permission to " + u.name);
333333
Base.addRight(u, item._id, item.name, [Rights.read], false);
334334
u = this.ensureResource(u);
335335
const _ot_end1 = Logger.otel.startTimer();
336336
await this.db.collection("users").updateOne({ _id: u._id }, { $set: { _acl: u._acl } });
337337
Logger.otel.endTimer(_ot_end1, DatabaseConnection.mongodb_update, { collection: "users" });
338338
} else if (u._id != item._id) {
339-
Logger.instanse.debug(item.name + " allready exists on " + u.name);
339+
Logger.instanse.silly(item.name + " allready exists on " + u.name);
340340
}
341341
} else if (arr[0]._type === "role") {
342342
let r: Role = Role.assign(arr[0]);
343343
if (r._id !== WellknownIds.admins && r._id !== WellknownIds.users && !Base.hasRight(r, item._id, Rights.read)) {
344-
Logger.instanse.debug("Assigning " + item.name + " read permission to " + r.name);
344+
Logger.instanse.silly("Assigning " + item.name + " read permission to " + r.name);
345345
Base.addRight(r, item._id, item.name, [Rights.read], false);
346346
r = this.ensureResource(r);
347347
const _ot_end2 = Logger.otel.startTimer();
348348
await this.db.collection("users").updateOne({ _id: r._id }, { $set: { _acl: r._acl } });
349349
Logger.otel.endTimer(_ot_end2, DatabaseConnection.mongodb_update, { collection: "users" });
350350
} else if (r._id != item._id) {
351-
Logger.instanse.debug(item.name + " allready exists on " + r.name);
351+
Logger.instanse.silly(item.name + " allready exists on " + r.name);
352352
}
353353

354354
}

OpenFlow/src/Logger.ts

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,12 @@ const path = require('path');
66
export class Logger {
77
public static otel: otel;
88
public static License: LicenseFile;
9+
static myFormat = winston.format.printf(info => {
10+
if (info instanceof Error || info.stack) {
11+
return `${info.timestamp} [${info.level}] ${info.message} \n ${info.stack}`;
12+
}
13+
return `${info.timestamp} [${info.level}] ${info.message}`;
14+
});
915
static configure(skipotel: boolean, skiplic: boolean): winston.Logger {
1016
const filename = path.join(Config.logpath, "openflow.log");
1117
const options: any = {
@@ -25,18 +31,12 @@ export class Logger {
2531
colorize: true
2632
},
2733
};
28-
const myFormat = winston.format.printf(info => {
29-
if (info instanceof Error || info.stack) {
30-
return `${info.timestamp} [${info.level}] ${info.message} \n ${info.stack}`;
31-
}
32-
return `${info.timestamp} [${info.level}] ${info.message}`;
33-
});
3434
options.console.format = winston.format.combine(
3535
winston.format.errors({ stack: true }),
3636
winston.format.timestamp({ format: 'HH:mm:ss.sss' }),
3737
winston.format.colorize(),
3838
winston.format.json(),
39-
myFormat
39+
Logger.myFormat
4040
);
4141
const logger: winston.Logger = winston.createLogger({
4242
level: "debug",
@@ -45,7 +45,7 @@ export class Logger {
4545
winston.format.errors({ stack: true }),
4646
winston.format.timestamp({ format: 'HH:mm:ss.sss' }),
4747
winston.format.json(),
48-
myFormat
48+
Logger.myFormat
4949
),
5050
transports: [
5151
new winston.transports.File(options.file),

OpenFlow/src/LoginProvider.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1006,7 +1006,7 @@ export class LoginProvider {
10061006
user = new User(); user.name = username; user.username = username;
10071007
await Crypt.SetPassword(user, password, span);
10081008
const jwt: string = Crypt.rootToken();
1009-
user = await DBHelper.ensureUser(jwt, user.name, user.username, null, password, span);
1009+
user = await DBHelper.EnsureUser(jwt, user.name, user.username, null, password, span);
10101010

10111011
const admins: Role = await DBHelper.FindRoleByName("admins", span);
10121012
admins.AddMember(user);
@@ -1035,7 +1035,7 @@ export class LoginProvider {
10351035
if (!createUser) {
10361036
return done(null, false);
10371037
}
1038-
user = await DBHelper.ensureUser(Crypt.rootToken(), username, username, null, password, span);
1038+
user = await DBHelper.EnsureUser(Crypt.rootToken(), username, username, null, password, span);
10391039
} else {
10401040
if (user.disabled) {
10411041
Audit.LoginFailed(username, "weblogin", "local", remoteip, "browser", "unknown", span);
@@ -1156,7 +1156,7 @@ export class LoginProvider {
11561156
}
11571157
if (NoderedUtil.IsNullEmpty(_user.name)) { done("Cannot add new user, name is empty, please add displayname to claims", null); return; }
11581158
const jwt: string = Crypt.rootToken();
1159-
_user = await DBHelper.ensureUser(jwt, _user.name, _user.username, null, null, span);
1159+
_user = await DBHelper.EnsureUser(jwt, _user.name, _user.username, null, null, span);
11601160
}
11611161
} else {
11621162
if (!NoderedUtil.IsNullUndefinded(_user)) {
@@ -1230,7 +1230,7 @@ export class LoginProvider {
12301230
_user.username = username;
12311231
(_user as any).mobile = profile.mobile;
12321232
if (NoderedUtil.IsNullEmpty(_user.name)) { done("Cannot add new user, name is empty.", null); return; }
1233-
_user = await DBHelper.ensureUser(jwt, _user.name, _user.username, null, null, span);
1233+
_user = await DBHelper.EnsureUser(jwt, _user.name, _user.username, null, null, span);
12341234
}
12351235
}
12361236
if (NoderedUtil.IsNullUndefinded(_user)) {

OpenFlow/src/Messages/Message.spec.ts

Lines changed: 0 additions & 37 deletions
This file was deleted.

0 commit comments

Comments
 (0)