Software: Apache. PHP/8.1.30 uname -a: Linux server1.tuhinhossain.com 5.15.0-163-generic #173-Ubuntu SMP Tue Oct 14 17:51:00 UTC uid=1002(picotech) gid=1003(picotech) groups=1003(picotech),0(root) Safe-mode: OFF (not secure) /home/picotech/domains/note.picotech.app/public_html/src/models/ drwxr-xr-x | |
| Viewing file: Select action/file-type: const { DataTypes } = require('sequelize');
const crypto = require('crypto');
const { sequelize } = require('../config/database');
const ApiKey = sequelize.define('ApiKey', {
service_name: {
type: DataTypes.STRING(100),
allowNull: false,
validate: {
notEmpty: true
}
},
key_type: {
type: DataTypes.ENUM('api_key', 'client_id', 'client_secret', 'access_token', 'refresh_token'),
allowNull: false,
validate: {
isIn: [['api_key', 'client_id', 'client_secret', 'access_token', 'refresh_token']]
}
},
key_value: {
type: DataTypes.TEXT,
allowNull: false,
validate: {
notEmpty: true
}
},
is_active: {
type: DataTypes.BOOLEAN,
allowNull: false,
defaultValue: true
},
expires_at: {
type: DataTypes.DATE,
allowNull: true
},
last_used_at: {
type: DataTypes.DATE,
allowNull: true
},
usage_count: {
type: DataTypes.INTEGER,
allowNull: false,
defaultValue: 0,
validate: {
min: 0
}
},
rate_limit_remaining: {
type: DataTypes.INTEGER,
allowNull: true,
validate: {
min: 0
}
},
rate_limit_reset_at: {
type: DataTypes.DATE,
allowNull: true
},
metadata: {
type: DataTypes.JSON,
allowNull: true,
defaultValue: {}
}
}, {
sequelize,
modelName: 'ApiKey',
tableName: 'api_keys',
timestamps: true,
indexes: [
{
fields: ['service_name']
},
{
fields: ['is_active']
},
{
fields: ['expires_at']
},
{
unique: true,
fields: ['service_name', 'key_type'],
name: 'unique_service_key_type'
}
]
});
// Static methods for managing API keys
ApiKey.getActiveKey = async function(serviceName, keyType = 'api_key') {
const key = await this.findOne({
where: {
service_name: serviceName,
key_type: keyType,
is_active: true,
[sequelize.Op.or]: [
{ expires_at: null },
{ expires_at: { [sequelize.Op.gt]: new Date() } }
]
},
order: [['last_used_at', 'ASC']] // Use least recently used key
});
if (!key) {
throw new Error(`No active API key found for service: ${serviceName}`);
}
return key;
};
ApiKey.getDecryptedKey = async function(serviceName, keyType = 'api_key') {
const key = await this.getActiveKey(serviceName, keyType);
// Update usage statistics
key.usage_count += 1;
key.last_used_at = new Date();
await key.save();
// Decrypt the key value
return this.decryptKeyValue(key.key_value);
};
ApiKey.setKey = async function(serviceName, keyType, plainKeyValue, metadata = {}) {
const encryptedValue = this.encryptKeyValue(plainKeyValue);
const [key, created] = await this.findOrCreate({
where: {
service_name: serviceName,
key_type: keyType
},
defaults: {
service_name: serviceName,
key_type: keyType,
key_value: encryptedValue,
is_active: true,
metadata
}
});
if (!created) {
key.key_value = encryptedValue;
key.is_active = true;
key.metadata = { ...key.metadata, ...metadata };
await key.save();
}
return key;
};
ApiKey.deactivateKey = async function(serviceName, keyType) {
const result = await this.update(
{ is_active: false },
{
where: {
service_name: serviceName,
key_type: keyType
}
}
);
return result[0] > 0;
};
ApiKey.rotateKey = async function(serviceName, keyType, newPlainKeyValue, metadata = {}) {
// Deactivate old key
await this.deactivateKey(serviceName, keyType);
// Set new key
return await this.setKey(serviceName, keyType, newPlainKeyValue, metadata);
};
ApiKey.checkRateLimit = async function(serviceName, keyType = 'api_key') {
const key = await this.findOne({
where: {
service_name: serviceName,
key_type: keyType,
is_active: true
}
});
if (!key || !key.rate_limit_remaining) {
return true; // No rate limit set
}
const now = new Date();
// Reset rate limit if expired
if (key.rate_limit_reset_at && key.rate_limit_reset_at <= now) {
key.rate_limit_remaining = key.metadata?.rate_limit_max || 1000;
key.rate_limit_reset_at = new Date(now.getTime() + (key.metadata?.rate_limit_window || 3600000)); // 1 hour default
await key.save();
}
return key.rate_limit_remaining > 0;
};
ApiKey.consumeRateLimit = async function(serviceName, keyType = 'api_key') {
const key = await this.findOne({
where: {
service_name: serviceName,
key_type: keyType,
is_active: true
}
});
if (key && key.rate_limit_remaining) {
key.rate_limit_remaining -= 1;
await key.save();
}
};
// Encryption/Decryption methods
ApiKey.encryptKeyValue = function(plainValue) {
const algorithm = 'aes-256-cbc';
const key = crypto.scryptSync(process.env.ENCRYPTION_KEY || 'default-key-change-in-production', 'salt', 32);
const iv = crypto.randomBytes(16);
const cipher = crypto.createCipheriv(algorithm, key, iv);
let encrypted = cipher.update(plainValue, 'utf8', 'hex');
encrypted += cipher.final('hex');
// Return format: iv:encryptedData
return iv.toString('hex') + ':' + encrypted;
};
ApiKey.decryptKeyValue = function(encryptedValue) {
try {
const algorithm = 'aes-256-cbc';
const key = crypto.scryptSync(process.env.ENCRYPTION_KEY || 'default-key-change-in-production', 'salt', 32);
const parts = encryptedValue.split(':');
if (parts.length !== 2) {
throw new Error('Invalid encrypted key format');
}
const iv = Buffer.from(parts[0], 'hex');
const encrypted = parts[1];
const decipher = crypto.createDecipheriv(algorithm, key, iv);
let decrypted = decipher.update(encrypted, 'hex', 'utf8');
decrypted += decipher.final('utf8');
return decrypted;
} catch (error) {
throw new Error('Failed to decrypt API key');
}
};
// Clean up expired keys
ApiKey.cleanupExpiredKeys = async function() {
const result = await this.update(
{ is_active: false },
{
where: {
expires_at: { [sequelize.Op.lt]: new Date() },
is_active: true
}
}
);
return result[0];
};
module.exports = ApiKey; |
:: Command execute :: | |
--[ c99shell v. 2.5 [PHP 8 Update] [24.05.2025] | Generation time: 0.0032 ]-- |