auth bugfix + licences
This commit is contained in:
@@ -135,7 +135,7 @@ async resolvePermissions(objectGuid) {
|
||||
sAMAccountName: user.sAMAccountName
|
||||
},
|
||||
this.SECRET_KEY,
|
||||
{ expiresIn: '10s' }
|
||||
{ expiresIn: '1y' }
|
||||
);
|
||||
|
||||
user.refreshtoken = token;
|
||||
@@ -197,7 +197,17 @@ async resolvePermissions(objectGuid) {
|
||||
|
||||
authenticate() {
|
||||
return async (req, res, next) => {
|
||||
|
||||
try {
|
||||
|
||||
// 🔥 SKIP PUBLIC ROUTES
|
||||
if (
|
||||
req.path.startsWith('/login') ||
|
||||
req.path.startsWith('/public')
|
||||
) {
|
||||
return next();
|
||||
}
|
||||
|
||||
const sAMAccountName = req.cookies?.sAMAccountName;
|
||||
|
||||
if (!sAMAccountName) {
|
||||
@@ -206,23 +216,30 @@ async resolvePermissions(objectGuid) {
|
||||
|
||||
const user = await this.findUser(sAMAccountName);
|
||||
|
||||
if (!user || !user.refreshtoken || !user.active) {
|
||||
if (!user || !user.active) {
|
||||
return res.redirect('/login');
|
||||
}
|
||||
|
||||
let payload;
|
||||
|
||||
try {
|
||||
payload = jwt.verify(user.refreshtoken, this.SECRET_KEY);
|
||||
} catch {
|
||||
return res.redirect('/login');
|
||||
}
|
||||
|
||||
// jwt.verify(user.refreshtoken, this.SECRET_KEY);
|
||||
this.verifyUserToken(sAMAccountName)
|
||||
// 🔥 LIVE RBAC RESOLUTION (bei JEDEM REQUEST)
|
||||
const rbac = await this.resolvePermissions(user.ObjectGUID);
|
||||
|
||||
req.user = {
|
||||
...user.toJSON(),
|
||||
jwt: payload,
|
||||
groups: rbac.groups,
|
||||
roles: rbac.roles,
|
||||
permissions: rbac.permissions
|
||||
};
|
||||
console.log(req.user)
|
||||
|
||||
next();
|
||||
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
return res.redirect('/login');
|
||||
|
||||
199
src/services/vaultifyManager.js
Normal file
199
src/services/vaultifyManager.js
Normal file
@@ -0,0 +1,199 @@
|
||||
const crypto = require('crypto');
|
||||
|
||||
class VaultifyManager {
|
||||
|
||||
constructor({
|
||||
vaultModel,
|
||||
publicKey
|
||||
}) {
|
||||
this.Vault = vaultModel;
|
||||
this.publicKey = publicKey;
|
||||
|
||||
this.cache = new Map(); // feature cache per customer
|
||||
}
|
||||
|
||||
|
||||
createMiddleware() {
|
||||
|
||||
return async (req, res, next) => {
|
||||
|
||||
const customerId = req.user?.Customer_ID;
|
||||
|
||||
if (!customerId) {
|
||||
return res.status(403).send('No customer');
|
||||
}
|
||||
|
||||
await this.loadCustomer(customerId);
|
||||
|
||||
req.vault = {
|
||||
has: (f) => this.has(customerId, f),
|
||||
get: (f, p) => this.get(customerId, f, p)
|
||||
};
|
||||
|
||||
next();
|
||||
};
|
||||
}
|
||||
|
||||
// =========================================================
|
||||
// LOAD ALL LICENSES FOR CUSTOMER
|
||||
// =========================================================
|
||||
|
||||
async loadCustomer(customerId) {
|
||||
|
||||
const records = await this.Vault.findAll({
|
||||
where: {
|
||||
Customer_ID: customerId,
|
||||
Active: true
|
||||
}
|
||||
});
|
||||
|
||||
const resultMap = new Map();
|
||||
|
||||
for (const record of records) {
|
||||
|
||||
const valid = this.verify(record);
|
||||
if (!valid) continue;
|
||||
|
||||
const payload = this.parsePayload(record.Payload);
|
||||
|
||||
resultMap.set(record.Feature, {
|
||||
payload,
|
||||
expiresAt: record.ExpiresAt
|
||||
});
|
||||
}
|
||||
|
||||
this.cache.set(customerId, resultMap);
|
||||
|
||||
return {
|
||||
customerId,
|
||||
features: [...resultMap.keys()]
|
||||
};
|
||||
}
|
||||
|
||||
// =========================================================
|
||||
// VERIFY SIGNATURE
|
||||
// =========================================================
|
||||
|
||||
verify(record) {
|
||||
|
||||
try {
|
||||
const data = {
|
||||
Customer_ID: record.Customer_ID,
|
||||
Feature: record.Feature,
|
||||
Payload: this.parsePayload(record.Payload),
|
||||
ExpiresAt: record.ExpiresAt
|
||||
};
|
||||
|
||||
const verifier = crypto.createVerify('RSA-SHA256');
|
||||
|
||||
verifier.update(JSON.stringify(data));
|
||||
verifier.end();
|
||||
|
||||
return verifier.verify(
|
||||
this.publicKey,
|
||||
record.Signature,
|
||||
'base64'
|
||||
);
|
||||
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// =========================================================
|
||||
// SAFE JSON PARSER
|
||||
// =========================================================
|
||||
|
||||
parsePayload(payload) {
|
||||
try {
|
||||
return typeof payload === 'string'
|
||||
? JSON.parse(payload)
|
||||
: payload;
|
||||
} catch {
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
// =========================================================
|
||||
// FEATURE CHECK
|
||||
// =========================================================
|
||||
|
||||
has(customerId, feature) {
|
||||
|
||||
const customer = this.cache.get(customerId);
|
||||
if (!customer) return false;
|
||||
|
||||
const entry = customer.get(feature);
|
||||
if (!entry) return false;
|
||||
|
||||
if (entry.expiresAt && new Date(entry.expiresAt) < new Date()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// =========================================================
|
||||
// GET FEATURE CONFIG
|
||||
// =========================================================
|
||||
|
||||
get(customerId, feature, path = null) {
|
||||
|
||||
const customer = this.cache.get(customerId);
|
||||
if (!customer) return undefined;
|
||||
|
||||
const entry = customer.get(feature);
|
||||
if (!entry) return undefined;
|
||||
|
||||
if (!path) return entry.payload;
|
||||
|
||||
return path
|
||||
.split('.')
|
||||
.reduce((obj, key) => obj?.[key], entry.payload);
|
||||
}
|
||||
|
||||
// =========================================================
|
||||
// REFRESH SINGLE FEATURE
|
||||
// =========================================================
|
||||
|
||||
async refreshFeature(customerId, feature) {
|
||||
|
||||
const record = await this.Vault.findOne({
|
||||
where: {
|
||||
Customer_ID: customerId,
|
||||
Feature: feature,
|
||||
Active: true
|
||||
}
|
||||
});
|
||||
|
||||
if (!record) return false;
|
||||
|
||||
if (!this.verify(record)) return false;
|
||||
|
||||
const customer = this.cache.get(customerId) || new Map();
|
||||
|
||||
customer.set(feature, {
|
||||
payload: this.parsePayload(record.Payload),
|
||||
expiresAt: record.ExpiresAt
|
||||
});
|
||||
|
||||
this.cache.set(customerId, customer);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// =========================================================
|
||||
// STATUS
|
||||
// =========================================================
|
||||
|
||||
status(customerId) {
|
||||
const customer = this.cache.get(customerId);
|
||||
|
||||
return {
|
||||
customerId,
|
||||
features: customer ? [...customer.keys()] : []
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = VaultifyManager;
|
||||
Reference in New Issue
Block a user