'use strict'; const mongoose = require('mongoose'), Schema = mongoose.Schema; const { ApiKeyServices } = require('../helpers/constants'); /** * ApiKey model — stores hashed API keys for external data-export consumers. * * Flow: * 1. POST /api/keys → generate random key, store prefix (first 8 chars) + bcrypt hash, return plain key ONCE. * 2. Subsequent requests supply X-API-Key header → middleware does prefix lookup + bcrypt.compare. * 3. On match, middleware sets req.uid = key.owner so all existing ownership filters work unchanged. * * Security notes: * - Plain key is NEVER stored. Only the bcrypt hash is persisted. * - Key prefix (first 8 chars) is stored in clear text for efficient DB lookup before comparing hashes. * - lastUsedAt is updated async (fire-and-forget) to avoid adding latency to the request path. */ const schema = new Schema({ owner: { type: Schema.Types.ObjectId, ref: 'User', required: true, index: true }, label: { type: String, required: true, trim: true, maxlength: 100 }, prefix: { type: String, required: true, index: true, maxlength: 8 }, // first 8 chars of plain key, stored for O(1) candidate lookup keyHash: { type: String, required: true }, // bcrypt hash of the full plain key service: { type: String, enum: Object.values(ApiKeyServices), default: ApiKeyServices.DATA_EXPORT, index: true }, // which service/integration this key grants access to active: { type: Boolean, default: true, index: true }, managedBy: { type: String, enum: ['owner', 'admin'], default: 'owner' }, createdAt: { type: Date, default: Date.now }, lastUsedAt: { type: Date }, requestCount: { type: Number, default: 0 } }); module.exports = mongoose.model('ApiKey', schema);