diff --git a/backend/app/administration.go b/backend/app/administration.go index 4b3d59b..4bc62c2 100644 --- a/backend/app/administration.go +++ b/backend/app/administration.go @@ -80,10 +80,11 @@ const ( ROUTE_V1_INSTALL = "/api/v1/install" ROUTE_V1_INSTALL_TEMPLATES = "/api/v1/install/templates" // domain - ROUTE_V1_DOMAIN = "/api/v1/domain" - ROUTE_V1_DOMAIN_SUBSET = "/api/v1/domain/subset" - ROUTE_V1_DOMAIN_ID = "/api/v1/domain/:id" - ROUTE_V1_DOMAIN_NAME = "/api/v1/domain/name/:domain" + ROUTE_V1_DOMAIN = "/api/v1/domain" + ROUTE_V1_DOMAIN_SUBSET = "/api/v1/domain/subset" + ROUTE_V1_DOMAIN_SUBSET_NO_PROXIES = "/api/v1/domain/subset/noproxies" + ROUTE_V1_DOMAIN_ID = "/api/v1/domain/:id" + ROUTE_V1_DOMAIN_NAME = "/api/v1/domain/name/:domain" // page ROUTE_V1_PAGE = "/api/v1/page" ROUTE_V1_PAGE_OVERVIEW = "/api/v1/page/overview" @@ -294,6 +295,7 @@ func setupRoutes( // domain GET(ROUTE_V1_DOMAIN, middleware.SessionHandler, controllers.Domain.GetAll). GET(ROUTE_V1_DOMAIN_SUBSET, middleware.SessionHandler, controllers.Domain.GetAllOverview). + GET(ROUTE_V1_DOMAIN_SUBSET_NO_PROXIES, middleware.SessionHandler, controllers.Domain.GetAllOverviewWithoutProxies). GET(ROUTE_V1_DOMAIN_ID, middleware.SessionHandler, controllers.Domain.GetByID). GET(ROUTE_V1_DOMAIN_NAME, middleware.SessionHandler, controllers.Domain.GetByName). POST(ROUTE_V1_DOMAIN, middleware.SessionHandler, controllers.Domain.Create). diff --git a/backend/controller/domain.go b/backend/controller/domain.go index 26a3028..0be0ad2 100644 --- a/backend/controller/domain.go +++ b/backend/controller/domain.go @@ -109,6 +109,34 @@ func (d *Domain) GetAllOverview(g *gin.Context) { d.Response.OK(g, domains) } +// GetAllOverviewWithoutProxies gets domains with limited data, excluding proxy domains for asset management +func (d *Domain) GetAllOverviewWithoutProxies(g *gin.Context) { + // handle session + session, _, ok := d.handleSession(g) + if !ok { + return + } + // parse request + companyID := companyIDFromRequestQuery(g) + queryArgs, ok := d.handleQueryArgs(g) + if !ok { + return + } + queryArgs.DefaultSortByUpdatedAt() + queryArgs.RemapOrderBy(DomainColumnsMap) + // get domains excluding proxy domains for asset management + domains, err := d.DomainService.GetAllOverviewWithoutProxies( + companyID, + g.Request.Context(), + session, + queryArgs, + ) + if ok := d.handleErrors(g, err); !ok { + return + } + d.Response.OK(g, domains) +} + // GetByID gets a domain by id func (d *Domain) GetByID(g *gin.Context) { // handle session diff --git a/backend/repository/domain.go b/backend/repository/domain.go index f69ab42..51dc482 100644 --- a/backend/repository/domain.go +++ b/backend/repository/domain.go @@ -23,7 +23,8 @@ var domainAllowedColumns = assignTableToColumns(database.DOMAIN_TABLE, []string{ // DomainOption is for deciding if we should load full domain entities type DomainOption struct { *vo.QueryArgs - WithCompany bool + WithCompany bool + ExcludeProxyDomains bool } // Domain is a Domain repository @@ -143,6 +144,10 @@ func (r *Domain) GetAllSubset( ) (*model.Result[model.DomainOverview], error) { result := model.NewEmptyResult[model.DomainOverview]() db := withCompanyIncludingNullContext(r.DB, companyID, database.DOMAIN_TABLE) + // exclude proxy domains (MITM domains) if requested + if options.ExcludeProxyDomains { + db = db.Where("proxy_id IS NULL") + } db, err := useQuery(db, database.DOMAIN_TABLE, options.QueryArgs, domainAllowedColumns...) if err != nil { return result, errs.Wrap(err) diff --git a/backend/service/domain.go b/backend/service/domain.go index 5a13511..28e534e 100644 --- a/backend/service/domain.go +++ b/backend/service/domain.go @@ -343,6 +343,42 @@ func (d *Domain) GetAllOverview( return result, nil } +// GetAllOverviewWithoutProxies gets domains with limited data, excluding proxy domains for asset management +func (d *Domain) GetAllOverviewWithoutProxies( + companyID *uuid.UUID, // can be null + ctx context.Context, + session *model.Session, + queryArgs *vo.QueryArgs, +) (*model.Result[model.DomainOverview], error) { + result := model.NewEmptyResult[model.DomainOverview]() + ae := NewAuditEvent("Domain.GetAllOverviewWithoutProxies", session) + // check permissions + isAuthorized, err := IsAuthorized(session, data.PERMISSION_ALLOW_GLOBAL) + if err != nil && !errors.Is(err, errs.ErrAuthorizationFailed) { + d.LogAuthError(err) + return result, errs.Wrap(err) + } + if !isAuthorized { + d.AuditLogNotAuthorized(ae) + return result, errs.ErrAuthorizationFailed + } + // get domains excluding proxy domains for asset management + result, err = d.DomainRepository.GetAllSubset( + ctx, + companyID, + &repository.DomainOption{ + QueryArgs: queryArgs, + ExcludeProxyDomains: true, + }, + ) + if err != nil { + d.Logger.Errorw("failed to get domains subset for assets", "error", err) + return result, errs.Wrap(err) + } + // no audit on read + return result, nil +} + // GetByID is a function to get domain by id func (d *Domain) GetByID( ctx context.Context, diff --git a/frontend/src/lib/api/api.js b/frontend/src/lib/api/api.js index 35b9e6a..e05339e 100644 --- a/frontend/src/lib/api/api.js +++ b/frontend/src/lib/api/api.js @@ -1276,6 +1276,21 @@ export class API { return await getJSON( this.getPath(`/domain/subset?${appendQuery(options)}${this.appendCompanyQuery(companyID)}`) ); + }, + + /** + * get domains subsets excluding proxy domains + * + * @param {TableURLParams} options + * @param {string|null} companyID + * @returns {Promise} + */ + getAllSubsetWithoutProxies: async (options, companyID = null) => { + return await getJSON( + this.getPath( + `/domain/subset/noproxies?${appendQuery(options)}${this.appendCompanyQuery(companyID)}` + ) + ); } }; diff --git a/frontend/src/routes/asset/+page.svelte b/frontend/src/routes/asset/+page.svelte index 295afca..23f8eb4 100644 --- a/frontend/src/routes/asset/+page.svelte +++ b/frontend/src/routes/asset/+page.svelte @@ -36,7 +36,7 @@ const refresh = async () => { try { isTableLoading = true; - const res = await api.domain.getAllSubset(tableURLParams, contextCompanyID); + const res = await api.domain.getAllSubsetWithoutProxies(tableURLParams, contextCompanyID); if (!res.success) { throw res.error; } diff --git a/frontend/src/routes/campaign-template/+page.svelte b/frontend/src/routes/campaign-template/+page.svelte index dd6ca90..56a61c6 100644 --- a/frontend/src/routes/campaign-template/+page.svelte +++ b/frontend/src/routes/campaign-template/+page.svelte @@ -135,14 +135,12 @@ const refreshDomains = async () => { const allDomains = await fetchAllRows((options) => { - return api.domain.getAllSubset(options, contextCompanyID); + return api.domain.getAllSubsetWithoutProxies(options, contextCompanyID); }); - // filter to only include regular domains (not proxy domains) - const regularDomains = allDomains.filter((domain) => domain.type !== 'proxy'); - domainMap = BiMap.FromArrayOfObjects(regularDomains); + domainMap = BiMap.FromArrayOfObjects(allDomains); // store full domain objects for type access domainObjectMap = new Map(); - regularDomains.forEach((domain) => { + allDomains.forEach((domain) => { domainObjectMap.set(domain.id, domain); }); }; diff --git a/frontend/src/routes/email/+page.svelte b/frontend/src/routes/email/+page.svelte index 5d6505e..4490819 100644 --- a/frontend/src/routes/email/+page.svelte +++ b/frontend/src/routes/email/+page.svelte @@ -120,7 +120,7 @@ const refreshDomains = async () => { const domains = await fetchAllRows((options) => { - return api.domain.getAllSubset(options, contextCompanyID); + return api.domain.getAllSubsetWithoutProxies(options, contextCompanyID); }); domainMap = BiMap.FromArrayOfObjects(domains); }; diff --git a/frontend/src/routes/page/+page.svelte b/frontend/src/routes/page/+page.svelte index 9419a2a..c64d658 100644 --- a/frontend/src/routes/page/+page.svelte +++ b/frontend/src/routes/page/+page.svelte @@ -108,7 +108,7 @@ const refreshAllDomains = async () => { const domains = await fetchAllRows((options) => { - return api.domain.getAllSubset(options, contextCompanyID); + return api.domain.getAllSubsetWithoutProxies(options, contextCompanyID); }); domainMap = BiMap.FromArrayOfObjects(domains); };