Merge pull request #11360 from overleaf/jpa-encrypt-2fa-secret

[web] two-factor-authentication: encrypt the secret in the db

GitOrigin-RevId: 86642e13d917b239012229f685ad0210039a6706
This commit is contained in:
Jakob Ackermann 2023-02-16 10:41:58 +00:00 committed by Copybot
parent 4f89588fb4
commit dd906df7b7
4 changed files with 64 additions and 15 deletions

View file

@ -167,7 +167,7 @@ const UserSchema = new Schema({
twoFactorAuthentication: {
createdAt: { type: Date },
enrolledAt: { type: Date },
secret: { type: String },
secretEncrypted: { type: String },
},
onboardingEmailSentAt: { type: Date },
splitTests: Schema.Types.Mixed,

View file

@ -0,0 +1,30 @@
const { batchedUpdate } = require('../scripts/helpers/batchedUpdate')
exports.tags = ['saas']
const batchedUpdateOptions = {
VERBOSE_LOGGING: 'true',
BATCH_SIZE: '1',
}
exports.migrate = async () => {
await batchedUpdate(
'users',
{ 'twoFactorAuthentication.secret': { $exists: true } },
{ $unset: { twoFactorAuthentication: true } },
null,
null,
batchedUpdateOptions
)
}
exports.rollback = async () => {
await batchedUpdate(
'users',
{ 'twoFactorAuthentication.secretEncrypted': { $exists: true } },
{ $unset: { twoFactorAuthentication: true } },
null,
null,
batchedUpdateOptions
)
}

View file

@ -1,18 +1,27 @@
const { ReadPreference, ObjectId } = require('mongodb')
const { db, waitForDb } = require('../../app/src/infrastructure/mongodb')
const BATCH_DESCENDING = process.env.BATCH_DESCENDING === 'true'
const BATCH_SIZE = parseInt(process.env.BATCH_SIZE, 10) || 1000
const VERBOSE_LOGGING = process.env.VERBOSE_LOGGING === 'true'
let BATCH_DESCENDING
let BATCH_SIZE
let VERBOSE_LOGGING
let BATCH_LAST_ID
if (process.env.BATCH_LAST_ID) {
BATCH_LAST_ID = ObjectId(process.env.BATCH_LAST_ID)
} else if (process.env.BATCH_RANGE_START) {
BATCH_LAST_ID = ObjectId(process.env.BATCH_RANGE_START)
}
let BATCH_RANGE_END
if (process.env.BATCH_RANGE_END) {
BATCH_RANGE_END = ObjectId(process.env.BATCH_RANGE_END)
refreshGlobalOptionsForBatchedUpdate()
function refreshGlobalOptionsForBatchedUpdate(options = {}) {
options = Object.assign({}, options, process.env)
BATCH_DESCENDING = options.BATCH_DESCENDING === 'true'
BATCH_SIZE = parseInt(options.BATCH_SIZE, 10) || 1000
VERBOSE_LOGGING = options.VERBOSE_LOGGING === 'true'
if (options.BATCH_LAST_ID) {
BATCH_LAST_ID = ObjectId(options.BATCH_LAST_ID)
} else if (options.BATCH_RANGE_START) {
BATCH_LAST_ID = ObjectId(options.BATCH_RANGE_START)
}
if (options.BATCH_RANGE_END) {
BATCH_RANGE_END = ObjectId(options.BATCH_RANGE_END)
}
}
async function getNextBatch(collection, query, maxId, projection, options) {
@ -56,13 +65,15 @@ async function batchedUpdate(
query,
update,
projection,
options
findOptions,
batchedUpdateOptions
) {
refreshGlobalOptionsForBatchedUpdate(batchedUpdateOptions)
await waitForDb()
const collection = db[collectionName]
options = options || {}
options.readPreference = ReadPreference.SECONDARY
findOptions = findOptions || {}
findOptions.readPreference = ReadPreference.SECONDARY
projection = projection || { _id: 1 }
let nextBatch
@ -74,7 +85,7 @@ async function batchedUpdate(
query,
maxId,
projection,
options
findOptions
)).length
) {
maxId = nextBatch[nextBatch.length - 1]._id

View file

@ -56,6 +56,14 @@ const overrides = {
// Disable contentful module.
contentful: undefined,
twoFactorAuthentication: {
accessTokenEncryptorOptions: {
cipherPasswords: {
'2023.1-v3': 'this-is-just-a-test-secret',
},
},
},
}
module.exports = baseApp.mergeWith(baseTest.mergeWith(overrides))