All files / services/config-service/src/models ApiKey.js

77.65% Statements 73/94
100% Branches 3/3
33.33% Functions 2/6
77.65% Lines 73/94

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 951x 1x 1x 1x 1x                 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x         1x 1x 1x         1x 1x 1x           1x 1x 1x  
const mongoose = require('mongoose');
const crypto = require('crypto');
 
const ALPHANUMERIC = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
 
function generateApiKey() {
  const chars = [];
  const bytes = crypto.randomBytes(44);
  for (let i = 0; i < 44; i++) {
    chars.push(ALPHANUMERIC[bytes[i] % ALPHANUMERIC.length]);
  }
  return 'nlm_' + chars.join('');
}
 
function hashApiKey(key) {
  return crypto.createHash('sha256').update(key).digest('hex');
}
 
const apiKeySchema = new mongoose.Schema({
  organizationId: {
    type: mongoose.Schema.Types.ObjectId,
    ref: 'Organization',
    required: true,
    index: true
  },
  name: {
    type: String,
    required: true,
    trim: true,
    maxlength: 100
  },
  keyHash: {
    type: String,
    required: true,
    unique: true
  },
  keyPrefix: {
    type: String,
    required: true
  },
  userId: {
    type: mongoose.Schema.Types.ObjectId,
    ref: 'User',
    default: null
  },
  isActive: {
    type: Boolean,
    default: true
  },
  keyValue: {
    type: String,
    default: null,
  },
  lastUsedAt: {
    type: Date,
    default: null
  }
}, {
  timestamps: true
});
 
apiKeySchema.index({ organizationId: 1, isActive: 1 });
 
apiKeySchema.statics.generateKey = generateApiKey;
apiKeySchema.statics.hashKey = hashApiKey;
 
apiKeySchema.statics.findByKey = async function(key) {
  const hash = hashApiKey(key);
  return this.findOne({ keyHash: hash });
};
 
apiKeySchema.methods.regenerate = function() {
  const newKey = generateApiKey();
  this.keyHash = hashApiKey(newKey);
  this.keyPrefix = newKey.slice(0, 8);
  return newKey;
};
 
apiKeySchema.methods.toJSON = function() {
  const obj = this.toObject();
  delete obj.keyHash;
  delete obj.__v;
  return obj;
};
 
apiKeySchema.methods.toJSONPublic = function() {
  const obj = this.toObject();
  delete obj.keyHash;
  delete obj.__v;
  delete obj.keyValue;
  return obj;
};
 
module.exports = mongoose.model('ApiKey', apiKeySchema);