From ede93add64f476051ecb4aaf53306b1241533303 Mon Sep 17 00:00:00 2001 From: Alex Holliday Date: Thu, 20 Aug 2026 13:57:24 -0700 Subject: [PATCH] add clear username flag --- server/src/api/validation/proxyValidation.ts | 2 +- .../proxies/proxy.repository.interface.ts | 2 +- .../domain/proxies/proxy.repository.mongo.ts | 13 +++++++++++-- server/src/domain/proxies/proxy.service.ts | 17 ++++++++++++----- 4 files changed, 25 insertions(+), 9 deletions(-) diff --git a/server/src/api/validation/proxyValidation.ts b/server/src/api/validation/proxyValidation.ts index a2e3edfa0..cab0ec2ea 100644 --- a/server/src/api/validation/proxyValidation.ts +++ b/server/src/api/validation/proxyValidation.ts @@ -14,9 +14,9 @@ export const createProxyBodyValidation = z.object({ password: z.string().optional(), }); -// Empty/absent password keeps doesn't delete, only clearPassword: true does. export const editProxyBodyValidation = createProxyBodyValidation.extend({ clearPassword: z.boolean().optional(), + clearUsername: z.boolean().optional(), }); export const getProxyByIdParamValidation = z.object({ diff --git a/server/src/domain/proxies/proxy.repository.interface.ts b/server/src/domain/proxies/proxy.repository.interface.ts index 17998392c..a235d0df4 100644 --- a/server/src/domain/proxies/proxy.repository.interface.ts +++ b/server/src/domain/proxies/proxy.repository.interface.ts @@ -7,7 +7,7 @@ export interface IProxiesRepository { findById(proxyId: string, teamId: string): Promise; findByTeamId(teamId: string): Promise; // update - updateById(proxyId: string, teamId: string, patch: Partial, options?: { unsetPassword?: boolean }): Promise; + updateById(proxyId: string, teamId: string, patch: Partial, options?: { unsetPassword?: boolean; unsetUsername?: boolean }): Promise; // delete deleteById(proxyId: string, teamId: string): Promise; } diff --git a/server/src/domain/proxies/proxy.repository.mongo.ts b/server/src/domain/proxies/proxy.repository.mongo.ts index 350411d7a..3ff810587 100644 --- a/server/src/domain/proxies/proxy.repository.mongo.ts +++ b/server/src/domain/proxies/proxy.repository.mongo.ts @@ -50,7 +50,12 @@ class MongoProxiesRepository implements IProxiesRepository { return proxies.map(this.toEntity); } - async updateById(proxyId: string, teamId: string, patch: Partial, options?: { unsetPassword?: boolean }): Promise { + async updateById( + proxyId: string, + teamId: string, + patch: Partial, + options?: { unsetPassword?: boolean; unsetUsername?: boolean } + ): Promise { try { const update: UpdateQuery = { $set: { @@ -59,7 +64,11 @@ class MongoProxiesRepository implements IProxiesRepository { }; if (options?.unsetPassword) { delete update.$set?.password; - update.$unset = { password: 1 }; + update.$unset = { ...update.$unset, password: 1 }; + } + if (options?.unsetUsername) { + delete update.$set?.username; + update.$unset = { ...update.$unset, username: 1 }; } const updatedProxy = await ProxyModel.findOneAndUpdate({ _id: proxyId, teamId }, update, { new: true, runValidators: true }); if (!updatedProxy) { diff --git a/server/src/domain/proxies/proxy.service.ts b/server/src/domain/proxies/proxy.service.ts index a57e3bfd5..265544d8c 100644 --- a/server/src/domain/proxies/proxy.service.ts +++ b/server/src/domain/proxies/proxy.service.ts @@ -8,7 +8,7 @@ export interface IProxiesService { createProxy(proxy: Partial, teamId: string): Promise; getProxy(proxyId: string, teamId: string): Promise; getProxiesByTeamId(teamId: string): Promise; - updateProxy(proxyId: string, teamId: string, patch: Partial & { clearPassword?: boolean }): Promise; + updateProxy(proxyId: string, teamId: string, patch: Partial & { clearPassword?: boolean; clearUsername?: boolean }): Promise; deleteProxy(proxyId: string, teamId: string): Promise; } @@ -47,16 +47,23 @@ export class ProxiesService implements IProxiesService { return clean; }; - updateProxy = async (proxyId: string, teamId: string, patch: Partial & { clearPassword?: boolean }): Promise => { - // Empty/absent password keeps the stored one; clearPassword removes it - const { clearPassword, ...proxyPatch } = patch; + updateProxy = async ( + proxyId: string, + teamId: string, + patch: Partial & { clearPassword?: boolean; clearUsername?: boolean } + ): Promise => { + // Empty/absent password and username don't delete, clearPassword / clearUsername does + const { clearPassword, clearUsername, ...proxyPatch } = patch; if (!proxyPatch.password) { delete proxyPatch.password; } if (!proxyPatch.username) { delete proxyPatch.username; } - const raw = await this.proxiesRepository.updateById(proxyId, teamId, proxyPatch, { unsetPassword: clearPassword === true }); + const raw = await this.proxiesRepository.updateById(proxyId, teamId, proxyPatch, { + unsetPassword: clearPassword === true, + unsetUsername: clearUsername === true, + }); return this.toResponse(raw); }; deleteProxy = async (proxyId: string, teamId: string): Promise => {