mirror of
https://github.com/HeyPuter/puter
synced 2024-11-14 22:06:00 +00:00
dev: allow app tokens to identify user sessions
This commit is contained in:
parent
bc51d4bd52
commit
6b8fbda14c
@ -22,6 +22,7 @@ const { get_user, get_app } = require("../../helpers");
|
|||||||
const { Context } = require("../../util/context");
|
const { Context } = require("../../util/context");
|
||||||
const APIError = require("../../api/APIError");
|
const APIError = require("../../api/APIError");
|
||||||
const { DB_WRITE } = require("../database/consts");
|
const { DB_WRITE } = require("../database/consts");
|
||||||
|
const { UUIDFPE } = require("../../util/uuidfpe");
|
||||||
|
|
||||||
const APP_ORIGIN_UUID_NAMESPACE = '33de3768-8ee0-43e9-9e73-db192b97a5d8';
|
const APP_ORIGIN_UUID_NAMESPACE = '33de3768-8ee0-43e9-9e73-db192b97a5d8';
|
||||||
|
|
||||||
@ -30,6 +31,7 @@ const LegacyTokenError = class extends Error {};
|
|||||||
class AuthService extends BaseService {
|
class AuthService extends BaseService {
|
||||||
static MODULES = {
|
static MODULES = {
|
||||||
jwt: require('jsonwebtoken'),
|
jwt: require('jsonwebtoken'),
|
||||||
|
crypto: require('crypto'),
|
||||||
uuidv5: require('uuid').v5,
|
uuidv5: require('uuid').v5,
|
||||||
uuidv4: require('uuid').v4,
|
uuidv4: require('uuid').v4,
|
||||||
}
|
}
|
||||||
@ -38,6 +40,11 @@ class AuthService extends BaseService {
|
|||||||
this.db = await this.services.get('database').get(DB_WRITE, 'auth');
|
this.db = await this.services.get('database').get(DB_WRITE, 'auth');
|
||||||
this.svc_session = await this.services.get('session');
|
this.svc_session = await this.services.get('session');
|
||||||
|
|
||||||
|
const uuid_fpe_key = this.config.uuid_fpe_key
|
||||||
|
? UUIDFPE.uuidToBuffer(this.config.uuid_fpe_key)
|
||||||
|
: this.modules.crypto.randomBytes(16);
|
||||||
|
this.uuid_fpe = new UUIDFPE(uuid_fpe_key);
|
||||||
|
|
||||||
this.sessions = {};
|
this.sessions = {};
|
||||||
|
|
||||||
const svc_token = await this.services.get('token');
|
const svc_token = await this.services.get('token');
|
||||||
@ -78,6 +85,12 @@ class AuthService extends BaseService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if ( decoded.type === 'app-under-user' ) {
|
if ( decoded.type === 'app-under-user' ) {
|
||||||
|
const session_uuid = this.uuid_fpe.decrypt(decoded.session);
|
||||||
|
const session = await this.get_session_(session_uuid);
|
||||||
|
|
||||||
|
if ( ! session ) {
|
||||||
|
throw APIError.create('token_auth_failed');
|
||||||
|
}
|
||||||
const user = await get_user({ uuid: decoded.user_uid });
|
const user = await get_user({ uuid: decoded.user_uid });
|
||||||
if ( ! user ) {
|
if ( ! user ) {
|
||||||
throw APIError.create('token_auth_failed');
|
throw APIError.create('token_auth_failed');
|
||||||
@ -164,6 +177,7 @@ class AuthService extends BaseService {
|
|||||||
version: '0.0.0',
|
version: '0.0.0',
|
||||||
user_uid: actor_type.user.uuid,
|
user_uid: actor_type.user.uuid,
|
||||||
app_uid,
|
app_uid,
|
||||||
|
session: this.uuid_fpe.encrypt(actor_type.session),
|
||||||
},
|
},
|
||||||
this.global_config.jwt_secret,
|
this.global_config.jwt_secret,
|
||||||
);
|
);
|
||||||
|
@ -81,6 +81,10 @@ const compression = {
|
|||||||
short: 'u',
|
short: 'u',
|
||||||
...uuid_compression(),
|
...uuid_compression(),
|
||||||
},
|
},
|
||||||
|
session: {
|
||||||
|
short: 's',
|
||||||
|
...uuid_compression(),
|
||||||
|
},
|
||||||
version: 'v',
|
version: 'v',
|
||||||
type: {
|
type: {
|
||||||
short: 't',
|
short: 't',
|
||||||
|
61
src/backend/src/util/uuidfpe.js
Normal file
61
src/backend/src/util/uuidfpe.js
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
const crypto = require('crypto');
|
||||||
|
|
||||||
|
class UUIDFPE {
|
||||||
|
static ALGORITHM = 'aes-128-ecb';
|
||||||
|
|
||||||
|
constructor(key) {
|
||||||
|
if ( !key || key.length !== 16 ) {
|
||||||
|
throw new Error('Key must be a 16-byte Buffer.');
|
||||||
|
}
|
||||||
|
this.key = key;
|
||||||
|
}
|
||||||
|
|
||||||
|
static uuidToBuffer (uuidStr) {
|
||||||
|
const hexStr = uuidStr.replace(/-/g, '');
|
||||||
|
return Buffer.from(hexStr, 'hex');
|
||||||
|
}
|
||||||
|
static bufferToUuid (buffer) {
|
||||||
|
const hexStr = buffer.toString('hex');
|
||||||
|
return [
|
||||||
|
hexStr.substring(0, 8),
|
||||||
|
hexStr.substring(8, 12),
|
||||||
|
hexStr.substring(12, 16),
|
||||||
|
hexStr.substring(16, 20),
|
||||||
|
hexStr.substring(20)
|
||||||
|
].join('-');
|
||||||
|
}
|
||||||
|
|
||||||
|
encrypt(uuidStr) {
|
||||||
|
const plaintext = this.constructor.uuidToBuffer(uuidStr);
|
||||||
|
|
||||||
|
const cipher = crypto.createCipheriv(
|
||||||
|
this.constructor.ALGORITHM,
|
||||||
|
this.key,
|
||||||
|
null,
|
||||||
|
);
|
||||||
|
cipher.setAutoPadding(false);
|
||||||
|
|
||||||
|
const encrypted = Buffer.concat([
|
||||||
|
cipher.update(plaintext),
|
||||||
|
cipher.final(),
|
||||||
|
]);
|
||||||
|
return this.constructor.bufferToUuid(encrypted);
|
||||||
|
}
|
||||||
|
|
||||||
|
decrypt(encryptedUuidStr) {
|
||||||
|
const encrypted = this.constructor.uuidToBuffer(encryptedUuidStr);
|
||||||
|
const decipher = crypto.createDecipheriv(
|
||||||
|
this.constructor.ALGORITHM,
|
||||||
|
this.key,
|
||||||
|
null,
|
||||||
|
);
|
||||||
|
decipher.setAutoPadding(false);
|
||||||
|
|
||||||
|
const decrypted = Buffer.concat([decipher.update(encrypted), decipher.final()]);
|
||||||
|
return this.constructor.bufferToUuid(decrypted);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
UUIDFPE,
|
||||||
|
};
|
Loading…
Reference in New Issue
Block a user