Skip to content

Commit

Permalink
Merge pull request #260 from skadefro/master
Browse files Browse the repository at this point in the history
Close 1.4.34
  • Loading branch information
skadefro authored Nov 28, 2022
2 parents 08d64dc + 30adf91 commit f6fc75b
Show file tree
Hide file tree
Showing 35 changed files with 592 additions and 521 deletions.
2 changes: 1 addition & 1 deletion .devcontainer.old/devcontainer.json
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@
// },
// Use 'postCreateCommand' to run commands after the container is created.
// "postCreateCommand": "npm i && cd OpenFlowNodeRED && npm i && cd .. && npm run build",
"postCreateCommand": "echo \"npm i && cd OpenFlowNodeRED && npm i && cd .. && npm run build\"",
"postCreateCommand": "echo \"npm install --omit=optional && cd OpenFlowNodeRED && npm install --omit=optional && cd .. && npm run build\"",
// Comment out connect as root instead. More info: https://aka.ms/vscode-remote/containers/non-root.
"remoteUser": "node",
"shutdownAction": "stopCompose"
Expand Down
8 changes: 5 additions & 3 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
FROM node:lts-alpine as builder

RUN npm i gulp typescript browserify tsify -g
RUN npm install --omit=optional gulp typescript browserify tsify -g

RUN mkdir /app
WORKDIR /app
COPY package*.json /app/
RUN npm install
RUN npm install --omit=optional
COPY . /app/
RUN gulp sass

Expand All @@ -19,7 +19,9 @@ EXPOSE 5858
WORKDIR /data
COPY --from=builder /app/package*.json .
COPY --from=builder /app/dist/ .
RUN npm install --omit=dev
# RUN npm install --omit=optional --omit=dev
# RUN npm install mongodb
RUN npm install --omit=dev --production

# ENTRYPOINT ["/usr/local/bin/node", "index.js"]
ENTRYPOINT ["/usr/local/bin/node", "--inspect=0.0.0.0:5858", "index.js"]
Expand Down
43 changes: 42 additions & 1 deletion OpenFlow/src/Audit.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Config } from "./Config";
import { TokenUser, Base, Rights, NoderedUtil } from "@openiap/openflow-api";
import { TokenUser, Base, Rights, NoderedUtil, WorkitemQueue } from "@openiap/openflow-api";
import { Crypt } from "./Crypt";
import { Span } from "@opentelemetry/api";
import { Logger } from "./Logger";
Expand Down Expand Up @@ -120,6 +120,27 @@ export class Audit {
Logger.otel.endSpan(span);
}
}
public static async AuditWorkitemPurge(user: TokenUser, wiq: WorkitemQueue, parent: Span): Promise<void> {
const span: Span = Logger.otel.startSubSpan("Audit.LoginSuccess", parent);
try {
Audit.ensure_openflow_logins();
Audit.openflow_logins?.add(1, { ...Logger.otel.defaultlabels, result: "success" });
const log: auditWorkitem = new auditWorkitem();
Base.addRight(log, user._id, user.name, [Rights.read, Rights.update, Rights.invoke]);
log.success = true;
log.userid = user._id;
log.name = user.name + " purged " + wiq.name;
log.username = user.username;
log.wiqid = wiq._id;
log.wiq = wiq.name;
await Config.db.InsertOne(log, "audit", 0, false, Crypt.rootToken(), span);
} catch (error) {
Logger.instanse.error(error, span);
}
finally {
Logger.otel.endSpan(span);
}
}
public static async NoderedAction(user: TokenUser, success: boolean, name: string, type: string, image: string, instancename: string, parent: Span): Promise<void> {
const span: Span = Logger.otel.startSubSpan("Audit.NoderedAction", parent);
try {
Expand Down Expand Up @@ -198,3 +219,23 @@ export class Nodered extends Base {
this._type = "nodered";
}
}
export class auditWorkitem extends Base {
public success: boolean;
public type: string;
public userid: string;
public username: string;
public image: string;
public imagename: string;
public imageversion: string;
public instancename: string;
public remoteip: string;
public ip: number;
public clientagent: string;
public clientversion: string;
public wiqid: string;
public wiq: string;
constructor() {
super();
this._type = "workitemqueue";
}
}
163 changes: 125 additions & 38 deletions OpenFlow/src/Config.ts

Large diffs are not rendered by default.

10 changes: 5 additions & 5 deletions OpenFlow/src/Crypt.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ export class Crypt {
}
static encrypt(text: string): string {
let iv: Buffer = crypto.randomBytes(Crypt.iv_length);
if (NoderedUtil.IsNullEmpty(Crypt.encryption_key)) Crypt.encryption_key = Config.aes_secret.substr(0, 32);
if (NoderedUtil.IsNullEmpty(Crypt.encryption_key)) Crypt.encryption_key = Config.aes_secret.substring(0, 32);
let cipher: crypto.CipherGCM = crypto.createCipheriv('aes-256-gcm', Buffer.from(Crypt.encryption_key), iv);
let encrypted: Buffer = cipher.update((text as any));
encrypted = Buffer.concat([encrypted, cipher.final()]);
Expand All @@ -60,7 +60,7 @@ export class Crypt {
let authTag: Buffer = null;
if (textParts.length > 0) authTag = Buffer.from(textParts.shift(), "hex");
let decrypted: Buffer;
if (NoderedUtil.IsNullEmpty(Crypt.encryption_key)) Crypt.encryption_key = Config.aes_secret.substr(0, 32);
if (NoderedUtil.IsNullEmpty(Crypt.encryption_key)) Crypt.encryption_key = Config.aes_secret.substring(0, 32);
if (authTag != null) {
let decipher: crypto.DecipherGCM = crypto.createDecipheriv('aes-256-gcm', Buffer.from(Crypt.encryption_key), iv);
decipher.setAuthTag(authTag);
Expand Down Expand Up @@ -114,7 +114,7 @@ export class Crypt {
user.selectedcustomerid = item.selectedcustomerid;
user.dblocked = item.dblocked;

if (NoderedUtil.IsNullEmpty(Crypt.encryption_key)) Crypt.encryption_key = Config.aes_secret.substr(0, 32);
if (NoderedUtil.IsNullEmpty(Crypt.encryption_key)) Crypt.encryption_key = Config.aes_secret.substring(0, 32);
const key = Crypt.encryption_key;
if (NoderedUtil.IsNullEmpty(Config.aes_secret)) throw new Error("Config missing aes_secret");
if (NoderedUtil.IsNullEmpty(key)) throw new Error("Config missing aes_secret");
Expand All @@ -126,7 +126,7 @@ export class Crypt {
if (NoderedUtil.IsNullEmpty(token)) {
throw new Error('jwt must be provided');
}
if (NoderedUtil.IsNullEmpty(Crypt.encryption_key)) Crypt.encryption_key = Config.aes_secret.substr(0, 32);
if (NoderedUtil.IsNullEmpty(Crypt.encryption_key)) Crypt.encryption_key = Config.aes_secret.substring(0, 32);
const o: any = jsonwebtoken.verify(token, Crypt.encryption_key);
let impostor: string = null;
if (!NoderedUtil.IsNullUndefinded(o) && !NoderedUtil.IsNullUndefinded(o.data) && !NoderedUtil.IsNullEmpty(o.data._id)) {
Expand Down Expand Up @@ -163,7 +163,7 @@ export class Crypt {
}
}
static decryptToken(token: string): any {
if (NoderedUtil.IsNullEmpty(Crypt.encryption_key)) Crypt.encryption_key = Config.aes_secret.substr(0, 32);
if (NoderedUtil.IsNullEmpty(Crypt.encryption_key)) Crypt.encryption_key = Config.aes_secret.substring(0, 32);
return jsonwebtoken.verify(token, Crypt.encryption_key);
}
}
110 changes: 93 additions & 17 deletions OpenFlow/src/DBHelper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import { LoginProvider, Provider } from "./LoginProvider";
import * as cacheManager from "cache-manager";
import { TokenRequest } from "./TokenRequest";
import { amqpwrapper } from "./amqpwrapper";
import { EntityRestriction } from "./DatabaseConnection";
// var cacheManager = require('cache-manager');
var redisStore = require('cache-manager-ioredis');
var mongoStore = require('@skadefro/cache-manager-mongodb');
Expand Down Expand Up @@ -103,6 +104,38 @@ export class DBHelper {
})
}
}
public async CheckCache(collectionname: string, item: Base, watch: boolean, frombroadcast: boolean, span: Span): Promise<void> {
await this.init();
if (watch && collectionname == "users" && item._id == WellknownIds.root) return;
if (collectionname == "config" && item._type == "resource") {
this.ResourceUpdate(item, watch, frombroadcast, span);
}
if (collectionname == "users" && (item._type == "user" || item._type == "role" || item._type == "customer")) {
this.UserRoleUpdate(item, watch, span);
}
if (collectionname == "mq") {
if (item._type == "queue") await this.QueueUpdate(item._id, item.name, watch, span);
if (item._type == "exchange") await this.ExchangeUpdate(item._id, item.name, watch, span);
if (item._type == "workitemqueue") await this.WorkitemQueueUpdate(item._id, watch, span);
}
if (collectionname == "workitems" && item._type == "workitem") {
// @ts-ignore
await this.WorkitemQueueUpdate(item.wiqid, true, span);
}
if (collectionname == "config" && (item._type == "restriction" || item._type == "resource" || item._type == "resourceusage")) {
this.clearCache("watch detected change in " + collectionname + " collection for a " + item._type + " " + item.name, span);
}
if (collectionname == "config" && item._type == "provider") {
await this.ClearProviders();
}
if (collectionname == "config" && item._type == "ipblock") {
await Logger.DBHelper.ClearIPBlockList();
}
if (collectionname === "config" && item._type === "restriction") {
await Logger.DBHelper.ClearEntityRestrictions();
}
}

async FindByIdWrap(_id, span: Span) {
Logger.instanse.debug("Add user to cache : " + _id, span);
return Config.db.getbyid<User>(_id, "users", Crypt.rootToken(), true, span);
Expand All @@ -128,6 +161,16 @@ export class DBHelper {
Logger.otel.endSpan(span);
}
}
private async ResourceUpdate(item: Base, watch: boolean, frombroadcast: boolean, span: Span): Promise<void> {
await this.init();
if (item.hasOwnProperty("userid")) {
// @ts-ignore
var key = ("resourceusage_" + item.userid).toString().toLowerCase();
this.DeleteKey(key, watch, frombroadcast, span);
} else {
this.DeleteKey("resource", watch, frombroadcast, span);
}
}
public GetResourcesWrap(span: Span) {
Logger.instanse.debug("Add resources user to cache", span);
return Config.db.query<Resource>({ query: { "_type": "resource" }, collectionname: "config", jwt: Crypt.rootToken() }, span);
Expand Down Expand Up @@ -192,9 +235,35 @@ export class DBHelper {
Logger.otel.endSpan(span);
}
}
public async ClearProviders() {
private async ClearProviders() {
await this.memoryCache.del("providers");
}
public GetEntityRestrictionsWrap(span) {
const rootjwt = Crypt.rootToken()
return Config.db.query<EntityRestriction>({ query: { "_type": "restriction" }, top: 1000, collectionname: "config", jwt: rootjwt }, span);
}
public async GetEntityRestrictions(parent: Span): Promise<EntityRestriction[]> {
await this.init();
const span: Span = Logger.otel.startSubSpan("dbhelper.GetProviders", parent);
try {
let items = await this.memoryCache.wrap("entityrestrictions", () => { return this.GetEntityRestrictionsWrap(span) });
let allowadmins = new EntityRestriction();
allowadmins.copyperm = false; allowadmins.collection = ""; allowadmins.paths = ["$."];
Base.addRight(allowadmins, WellknownIds.admins, "admins", [Rights.create]);
items.push(allowadmins);
for (let i = 0; i < items.length; i++) {
items[i] = EntityRestriction.assign(items[i]);
}
return items;
} catch (error) {
throw error;
} finally {
Logger.otel.endSpan(span);
}
}
public async ClearEntityRestrictions() {
await this.memoryCache.del("entityrestrictions");
}
public async FindRequestTokenID(key: string, parent: Span): Promise<TokenRequest> {
await this.init();
const span: Span = Logger.otel.startSubSpan("dbhelper.FindRequestTokenID", parent);
Expand Down Expand Up @@ -619,28 +688,33 @@ export class DBHelper {
}
public async DeleteKey(key: string, watch: boolean, frombroadcast: boolean, span: Span): Promise<void> {
if (!this._doClear(watch, span)) return;
// might have more than one api node, but don't have shared cache, so broadcast to all
if (Config.enable_openflow_amqp && Config.cache_store_type != "redis" && Config.cache_store_type != "mongodb") {
if (!Config.unittesting && !frombroadcast) {
Logger.instanse.debug("Send clearcache command for " + key, span);
amqpwrapper.Instance().send("openflow", "", { "command": "clearcache", "key": key }, 20000, null, "", span, 1);
}
} else if (!Config.enable_openflow_amqp) {
await Logger.DBHelper.memoryCache.del(key);
} else if (!Config.enable_openflow_amqp) { // only one api node, since not using queue, so remove key
await Logger.DBHelper.memoryCache.del(key);
} else if (!watch) { // more than one api node, but using shared cache, so only need to clear once
await Logger.DBHelper.memoryCache.del(key);
}
}
private _doClear(watch: boolean, span: Span) {
var doit: boolean = false;
if (watch) {
doit = false;
if (Config.cache_store_type != "redis" && Config.cache_store_type != "mongodb") {
doit = true;
}
} else {
doit = true;
}
return doit;
}
public async UserRoleUpdate(userrole: Base | TokenUser, watch: boolean, span: Span) {
return true;
// var doit: boolean = false;
// if (watch) {
// doit = false;
// if (Config.cache_store_type != "redis" && Config.cache_store_type != "mongodb") {
// doit = true;
// }
// } else {
// doit = true;
// }
// return doit;
}
private async UserRoleUpdate(userrole: Base | TokenUser, watch: boolean, span: Span) {
if (NoderedUtil.IsNullUndefinded(userrole)) return;
if (!this._doClear(watch, span)) return;
if (userrole._type == "user") {
Expand Down Expand Up @@ -681,12 +755,12 @@ export class DBHelper {
}

}
public async QueueUpdate(_id: string, name: string, watch: boolean, span: Span) {
private async QueueUpdate(_id: string, name: string, watch: boolean, span: Span) {
Logger.instanse.debug("Clear queue cache : " + name + " " + _id, span);
if (!NoderedUtil.IsNullEmpty(name)) await this.DeleteKey(("queuename_" + name).toString(), watch, false, span);
if (!NoderedUtil.IsNullEmpty(_id)) await this.DeleteKey(("mq_" + _id).toString(), watch, false, span);
}
public async ExchangeUpdate(_id: string, name: string, watch: boolean, span: Span) {
private async ExchangeUpdate(_id: string, name: string, watch: boolean, span: Span) {
Logger.instanse.debug("Clear exchange cache : " + name + " " + _id, span);
if (!NoderedUtil.IsNullEmpty(name)) await this.DeleteKey(("exchangename_" + name).toString(), watch, false, span);
if (!NoderedUtil.IsNullEmpty(_id)) await this.DeleteKey(("mq_" + _id).toString(), watch, false, span);
Expand All @@ -710,6 +784,7 @@ export class DBHelper {
await this.init();
const span: Span = Logger.otel.startSubSpan("dbhelper.GetPushableQueues", parent);
try {
if (!Config.cache_workitem_queues) return await this.GetPushableQueuesWrap(span);
let items = await this.memoryCache.wrap("pushablequeues", () => { return this.GetPushableQueuesWrap(span) });
return items;
} catch (error) {
Expand All @@ -730,6 +805,7 @@ export class DBHelper {
await this.init();
const span: Span = Logger.otel.startSubSpan("dbhelper.GetPendingWorkitemsCount", parent);
try {
if (!Config.cache_workitem_queues) return await this.GetPendingWorkitemsCountWrap(wiqid, span);
var key = ("pendingworkitems_" + wiqid).toString().toLowerCase();
let count = await this.memoryCache.wrap(key, () => { return this.GetPendingWorkitemsCountWrap(wiqid, span); });
return count;
Expand Down Expand Up @@ -900,7 +976,7 @@ export class DBHelper {
Logger.otel.endSpan(span);
}
}
public async ClearIPBlockList() {
private async ClearIPBlockList() {
await this.memoryCache.del("ipblock");
}
}
Loading

0 comments on commit f6fc75b

Please sign in to comment.