mirror of
https://github.com/linuxserver/gclient.git
synced 2026-02-20 02:54:19 +08:00
105 lines
3.0 KiB
JavaScript
105 lines
3.0 KiB
JavaScript
const crypto = require('crypto');
|
|
const fs = require('fs');
|
|
const path = require('path');
|
|
|
|
/**
|
|
* Function needed to encrypt the token string for guacamole connections
|
|
* @param {object} value - the value to encrypt
|
|
* @param {string} algorithm - the algorithm to use to encrypt
|
|
* @param {string} key - the key to encrypt with
|
|
* @returns {string} a base64 encoded string containing the encrypted data
|
|
*/
|
|
const encrypt = (value, algorithm, key) => {
|
|
const iv = crypto.randomBytes(16);
|
|
const cipher = crypto.createCipheriv(algorithm, key, iv);
|
|
let crypted = cipher.update(JSON.stringify(value), 'utf8', 'base64');
|
|
crypted += cipher.final('base64');
|
|
|
|
return Buffer.from(JSON.stringify({
|
|
iv: iv.toString('base64'),
|
|
value: crypted,
|
|
})).toString('base64');
|
|
};
|
|
|
|
/**
|
|
* Function to decrypt the guacamole connection token string
|
|
* @param {string} ciphertext - the encrypted ciphertext
|
|
* @param {*} algorithm - the algorithm used in encryption
|
|
* @param {*} key - the key used in encryption
|
|
* @param {*} iv - the base64-encoded iv used in encryption
|
|
* @returns {string} the decrypted ciphertext
|
|
*/
|
|
const decrypt = (ciphertext, algorithm, key, iv) => {
|
|
const decipher = crypto.createDecipheriv(algorithm, key, Buffer.from(iv, 'base64'));
|
|
const decrypted = decipher.update(ciphertext, 'base64', 'utf8');
|
|
return (decrypted + decipher.final('utf8'));
|
|
};
|
|
|
|
/**
|
|
* Normalizes a string that may or may not have a trailing slash (uri, path, etc.)
|
|
* @param {string} str
|
|
* @returns {string}
|
|
*/
|
|
const trimTrailingSlash = (str) => (str.charAt(str.length - 1) === '/' ? str.slice(0, -1) : str);
|
|
|
|
/**
|
|
* Determines if the given param is an Object
|
|
* @param {*} item
|
|
* @returns {boolean}
|
|
*/
|
|
const isObject = (item) => (item && typeof item === 'object' && !Array.isArray(item));
|
|
|
|
/**
|
|
* Deep-merges two objects without mutating either of the params
|
|
* @param {object} target
|
|
* @param {object} source
|
|
* @returns {object}
|
|
*/
|
|
const deepMerge = (target, source) => {
|
|
const output = Object.assign({}, target); // eslint-disable-line prefer-object-spread
|
|
|
|
if (isObject(target) && isObject(source)) {
|
|
Object.keys(source).forEach((key) => {
|
|
if (isObject(source[key])) {
|
|
if (!(key in target)) {
|
|
Object.assign(output, { [key]: source[key] });
|
|
} else {
|
|
output[key] = deepMerge(target[key], source[key]);
|
|
}
|
|
} else {
|
|
Object.assign(output, { [key]: source[key] });
|
|
}
|
|
});
|
|
}
|
|
|
|
return output;
|
|
};
|
|
|
|
/**
|
|
* Loads the credential config file from disk
|
|
* @param {string} dir
|
|
* @returns {object}
|
|
*/
|
|
const loadConfig = (dir) => {
|
|
const configPath = path.join(dir, 'config.json');
|
|
|
|
// Check if the config file exists (it always should but if it somehow isn't
|
|
// set or removed we default to our known abc/abc creds)
|
|
if (!fs.existsSync(configPath)) {
|
|
return {
|
|
username: 'abc',
|
|
password: 'abc',
|
|
};
|
|
}
|
|
|
|
return JSON.parse(fs.readFileSync(configPath));
|
|
};
|
|
|
|
module.exports = {
|
|
encrypt,
|
|
decrypt,
|
|
trimTrailingSlash,
|
|
deepMerge,
|
|
loadConfig,
|
|
};
|