Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

SK-246 added device_id field for encryption device record #129

Merged
merged 2 commits into from
Aug 23, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ CONVERSATION_MAX_PARTICIPANTS=50
CONVERSATION_PRELOAD_COUNT=1000
JWT_ACCESS_SECRET=token
JWT_ACCESS_TOKEN_EXPIRES_IN=10800
ENCRYPTION_DEVICE_TOKEN_EXPIRES_IN=2592000
OPERATIONS_LOG_EXPIRES_IN=1209600
NODE_CLUSTER_DATA_EXPIRES_IN=30000
REDIS_SUB_DATA_EXPIRES_IN=30000
Expand Down
14 changes: 2 additions & 12 deletions APIs/JSON/validations/encryption_schema_validation.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,17 +19,7 @@ export const encryptionSchemaValidation = {
cause: ERROR_STATUES.INCORRECT_SIGNED_KEY,
})
),
one_time_pre_keys: Joi.array()
.items(
Joi.string()
.max(255)
.error(
new Error(ERROR_STATUES.INCORRECT_ONE_TIME_PRE_KEYS.message, {
cause: ERROR_STATUES.INCORRECT_ONE_TIME_PRE_KEYS,
})
)
)
.max(100)
one_time_pre_keys: Joi.alternatives(Joi.object().max(100), Joi.array().items(Joi.string().max(255)).max(100))
.required()
.error(
new Error(ERROR_STATUES.INCORRECT_ONE_TIME_PRE_KEYS.message, {
Expand All @@ -56,6 +46,6 @@ export const encryptionSchemaValidation = {
),
}),
device_delete: Joi.object({
id: Joi.alternatives().try(Joi.number().max(255).required(), Joi.string().max(255).required()).required(),
device_id: Joi.alternatives().try(Joi.number().max(255).required(), Joi.string().max(255).required()).required(),
}),
}
2 changes: 1 addition & 1 deletion app/providers/operations/encryption/delete/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ class EncryptionDeleteOperation {
}

async perform(ws, deleteParams) {
const device = await this.encryptionService.encryptionRepo.findById(deleteParams.id)
const device = await this.encryptionService.encryptionRepo.findByDeviceId(deleteParams.device_id)

const userId = this.sessionService.getSessionUserId(ws)

Expand Down
2 changes: 1 addition & 1 deletion app/providers/operations/encryption/list/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,9 @@ class EncryptionListOperation {
const deviceList = await this.encryptionService.encryptionRepo.getAllUserDevices(userId)

return deviceList.map((obj) => ({
id: obj._id,
identity_key: obj.identity_key,
signed_key: obj.signed_key,
device_id: obj.device_id,
}))
}
}
Expand Down
6 changes: 3 additions & 3 deletions app/providers/operations/encryption/register/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,15 @@ class EncryptionRegisterOperation {

async perform(ws, registerDeviceParams) {
const userId = this.sessionService.getSessionUserId(ws)
const existingDevice = await this.encryptionService.encryptionRepo.findByIdentityKey(
registerDeviceParams.identity_key
)
const deviceId = this.sessionService.getDeviceId(ws, userId)
const existingDevice = await this.encryptionService.encryptionRepo.findByDeviceId(deviceId)

if (existingDevice) {
await this.encryptionService.update(existingDevice, registerDeviceParams)
} else {
await this.encryptionService.encryptionRepo.create({
user_id: userId,
device_id: deviceId,
...registerDeviceParams,
})
}
Expand Down
3 changes: 2 additions & 1 deletion app/providers/operations/user/logout/Provider.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,9 @@ class UserLogoutOperationRegisterProvider extends RegisterProvider {
register(slc) {
const sessionService = slc.use("SessionService")
const userTokenRepo = slc.use("UserTokenRepository")
const encryptionRepo = slc.use("EncryptionRepository")

return new UserLogoutOperation(sessionService, userTokenRepo)
return new UserLogoutOperation(sessionService, userTokenRepo, encryptionRepo)
}
}

Expand Down
5 changes: 4 additions & 1 deletion app/providers/operations/user/logout/index.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import { ERROR_STATUES } from "../../../../constants/errors.js"

class UserLogoutOperation {
constructor(sessionService, userTokenRepo) {
constructor(sessionService, userTokenRepo, encryptionRepo) {
this.sessionService = sessionService
this.userTokenRepo = userTokenRepo
this.encryptionRepo = encryptionRepo
}

async perform(ws) {
Expand All @@ -17,6 +18,8 @@ class UserLogoutOperation {

const deviceId = this.sessionService.getDeviceId(ws, userId)

await this.encryptionRepo.removeByDeviceId(userId, deviceId)

await this.sessionService.removeUserSession(ws, userId, deviceId)

await this.userTokenRepo.deleteByUserId(userId, deviceId)
Expand Down
17 changes: 9 additions & 8 deletions app/providers/repositories/encryption/index.js
Original file line number Diff line number Diff line change
@@ -1,14 +1,8 @@
import BaseRepository from "../base.js"

class EncryptionRepository extends BaseRepository {
async findByIdentityKey(identity_key) {
const device = await this.findOne({ identity_key })

return device
}

async findById(recordId) {
const device = await this.findOne({ _id: recordId })
async findByDeviceId(device_id) {
const device = await this.findOne({ device_id })

return device
}
Expand All @@ -19,6 +13,13 @@ class EncryptionRepository extends BaseRepository {
return device
}

async removeByDeviceId(user_id, device_id) {
const record = await this.findOne({ user_id, device_id })
if (record) {
await this.deleteById(record.params._id)
}
}

async getAllUserDevices(user_id) {
const devices = await this.findAll({ user_id })

Expand Down
17 changes: 10 additions & 7 deletions docs/API.md
Original file line number Diff line number Diff line change
Expand Up @@ -1359,7 +1359,10 @@ TBA
device_register: {
identity_key: "identity_key",
signed_key: "signed_key",
one_time_pre_keys: ["key_1", "key_2", "key_3", "key_4", ...],
one_time_pre_keys: ["key_1", "key_2", "key_3", "key_4", ...] || {
AAAAAAAAAA4: "...",
...
},
},
id: "421cda83-7f39-45a9-81e8-5f83cfa0733c"
}
Expand Down Expand Up @@ -1387,14 +1390,14 @@ TBA
response: {
devices: [
{
id: "63077ad836b78c3d82af0812",
device_id: "device_1",
signed_key: "signed_key1"
identity_key: "device_1",
signed_key: "signed_key1",
device_id: "device_1"
},
{
id: "63077ad836b78c3d82af0813",
identity_key: "identity_key2",
signed_key: "signed_key2"
signed_key: "signed_key2",
device_id: "device_2"
},
...
],
Expand Down Expand Up @@ -1451,7 +1454,7 @@ TBA
{
request: {
device_delete: {
id: "63077ad836b78c3d82af0813",
device_id: "63077ad836b78c3d82af0813",
},
id: "421cda83-7f39-45a9-81e8-5f83cfa0733c"
}
Expand Down
10 changes: 8 additions & 2 deletions migrations/20240812113744-set-encrypted-key-indexes.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,13 @@
export const up = async (db, client) => {
await db.collection("encrypted_devices").createIndex({ user_id: 1, identity_key: 1 }, { unique: true })
await db
.collection("encrypted_devices")
.createIndex({ updated_at: 1 }, { expireAfterSeconds: parseInt(process.env.ENCRYPTION_DEVICE_TOKEN_EXPIRES_IN) })
await db.collection("encrypted_devices").createIndex({ user_id: 1, device_id: 1 }, { unique: true })
await db.collection("encrypted_devices").createIndex({ device_id: 1 })
}

export const down = async (db, client) => {
await db.collection("encrypted_devices").dropIndex({ user_id: 1, identity_key: 1 })
await db.collection("encrypted_devices").dropIndex({ user_id: 1, device_id: 1 })
await db.collection("encrypted_devices").dropIndex({ device_id: 1 })
await db.collection("encrypted_devices").dropIndex({ updated_at: 1 })
}
20 changes: 11 additions & 9 deletions test/encryption.js
Original file line number Diff line number Diff line change
Expand Up @@ -135,16 +135,16 @@ describe("Encryption function", async () => {
let responseData = await packetJsonProcessor.processMessageOrError(mockedWS, JSON.stringify(requestData))
responseData = responseData.backMessages.at(0).response

userDeviceId = responseData.devices[0].id
userDeviceId = responseData.devices[0].device_id

assert.equal(responseData.id, requestData.id)
assert.equal(responseData.devices[0].signed_key, "test_key-1")
assert.equal(responseData.devices[0].identity_key, "test_key")
assert.notEqual(responseData.devices[0].device_id, null)
assert.equal(responseData.devices[0].one_time_pre_keys, null)
})

it("should work, by id", async () => {
await sendLogout(mockedWS, currentUserToken)
currentUserToken = (await sendLogin(mockedWS, "user_2")).response.user.token

const requestData = {
Expand Down Expand Up @@ -187,7 +187,7 @@ describe("Encryption function", async () => {
it("should fail, forbidden", async () => {
const requestData = {
device_delete: {
id: "user_19673",
device_id: "user_19673",
},
id: "1",
}
Expand All @@ -204,7 +204,7 @@ describe("Encryption function", async () => {

const requestData = {
device_delete: {
id: "312dfsszfg",
device_id: "312dfsszfg",
},
id: "1",
}
Expand All @@ -216,18 +216,20 @@ describe("Encryption function", async () => {
})

it("should fail, forbidden", async () => {
await sendLogout(mockedWS, currentUserToken)
currentUserToken = (await sendLogin(mockedWS, "user_2")).response.user.token

const requestData = {
device_delete: {
id: userDeviceId,
device_id: userDeviceId,
},
id: "2",
}
let responseData = await packetJsonProcessor.processMessageOrError(mockedWS, JSON.stringify(requestData))
responseData = responseData.backMessages.at(0).response
responseData = responseData.backMessages.at(0).device_delete

assert.equal(responseData.success, true)
assert.equal(responseData.id, requestData.id)
assert.deepEqual(responseData.error, undefined)
assert.notEqual(responseData, undefined)
assert.deepEqual(responseData.error, { status: 403, message: "Forbidden." })
})
})

Expand Down