diff --git a/migrations/metadata/actions.graphql b/migrations/metadata/actions.graphql index a047acde..01dd9251 100644 --- a/migrations/metadata/actions.graphql +++ b/migrations/metadata/actions.graphql @@ -4,12 +4,6 @@ type Mutation { ): DomainResult } -type Mutation { - create_or_update_certificate( - dns_hosted_zone_id: Int! - ): UpdateCertificateResult -} - type Mutation { create_record( record: RecordInput @@ -28,20 +22,6 @@ type Mutation { ): DeleteRecordsResult } -type Mutation { - resync_mailchimp_start( - is_community: Boolean - id: Int! - ): MailchimpStart -} - -type Query { - resync_mailchimp_status( - is_community: Boolean - id: Int! - ): MailchimpStatus -} - input DomainInput { domain_name: String! community_id: Int! diff --git a/migrations/metadata/actions.yaml b/migrations/metadata/actions.yaml index 2f1f3744..a1d7dc53 100644 --- a/migrations/metadata/actions.yaml +++ b/migrations/metadata/actions.yaml @@ -5,14 +5,6 @@ actions: handler: '{{API_DOMAINS_URL}}/actions/create-domain' permissions: - role: user - - name: create_or_update_certificate - definition: - kind: synchronous - handler: '{{API_DOMAINS_URL}}/actions/create-or-update-certificate' - permissions: - - role: common_user - - role: user - comment: This mutation update routers configuration based on traefik and etcd - name: create_record definition: kind: synchronous @@ -31,19 +23,6 @@ actions: handler: '{{API_DOMAINS_URL}}/actions/delete-record' permissions: - role: user - - name: resync_mailchimp_start - definition: - kind: synchronous - handler: '{{ACTION_BASE_URL}}/start-resync-mailchimp' - forward_client_headers: true - permissions: - - role: user - - name: resync_mailchimp_status - definition: - kind: "" - handler: '{{ACTION_BASE_URL}}/status-resync-mailchimp' - permissions: - - role: user custom_types: enums: [] input_objects: diff --git a/migrations/metadata/databases/default/tables/public_certificates.yaml b/migrations/metadata/databases/default/tables/public_certificates.yaml index 31d773fd..825927a0 100644 --- a/migrations/metadata/databases/default/tables/public_certificates.yaml +++ b/migrations/metadata/databases/default/tables/public_certificates.yaml @@ -31,14 +31,3 @@ select_permissions: community_users: user_id: _eq: X-Hasura-User-Id -event_triggers: - - name: check_certificate - definition: - enable_manual: false - insert: - columns: '*' - retry_conf: - interval_sec: 360 - num_retries: 20 - timeout_sec: 60 - webhook: '{{API_DOMAINS_URL}}/events/check-certificate' diff --git a/migrations/metadata/databases/default/tables/public_dns_hosted_zones.yaml b/migrations/metadata/databases/default/tables/public_dns_hosted_zones.yaml index ad978a32..641c2eb3 100644 --- a/migrations/metadata/databases/default/tables/public_dns_hosted_zones.yaml +++ b/migrations/metadata/databases/default/tables/public_dns_hosted_zones.yaml @@ -79,15 +79,3 @@ update_permissions: user_id: _eq: X-Hasura-User-Id check: null -event_triggers: - - name: create_certificate - definition: - enable_manual: true - update: - columns: - - ns_ok - retry_conf: - interval_sec: 10 - num_retries: 0 - timeout_sec: 60 - webhook: '{{API_DOMAINS_URL}}/events/create-certificate' diff --git a/packages/domains-api/src/controllers/certificates-controller.spec.ts b/packages/domains-api/src/controllers/certificates-controller.spec.ts deleted file mode 100644 index 4abb6403..00000000 --- a/packages/domains-api/src/controllers/certificates-controller.spec.ts +++ /dev/null @@ -1,382 +0,0 @@ -// Mock de certificates redis API (Padrão para todos os testes) -const mockCreateWildcard = jest.fn(); -const mockCreateRouters = jest.fn(); -const mockGetRouters = jest.fn(); - -jest.mock('../etcd-db/certificates', () => ({ - createWildcard: mockCreateWildcard, - createRouters: mockCreateRouters, - getRouters: mockGetRouters -})) - -import CertificatesController, { get_domain } from './certificates-controller'; - -describe('Certificates controller', () => { - // Mock de clients externos API e Redis (Padrão para todos os testes) - const mockGraphQLClient = { - request: jest.fn() - } - - beforeEach(() => { - jest.clearAllMocks(); - }) - - describe('certificate is create', () => { - // Mock de entradas da função (Padrão para testes que criam certificado) - const dns = { - id: 4, - community_id: 1, - domain_name: 'test.org', - ns_ok: true - }; - const request: any = { - body: { - event: { - data: { - new: dns - } - } - } - } - const mockJson = jest.fn(); - const response: any = { - status: jest.fn().mockImplementation(() => ({ - json: mockJson - })) - } - - it('should return graphql response to action', async () => { - const result = { - id: 3, - dns_hosted_zone_id: request.body.event.data.new.id, - is_active: false, - community_id: request.body.event.data.new.community_id, - domain: 'test.org', - } - - // Mock de clients externos API e Redis - mockGraphQLClient.request.mockResolvedValueOnce({ mobilizations: [] }); - mockGraphQLClient.request.mockResolvedValueOnce({ insert_certificates_one: result }); - - const certificatesController = new CertificatesController(mockGraphQLClient); - await certificatesController.create(request, response); - - expect(response.status.mock.calls[0][0]).toBe(200); - expect(mockJson.mock.calls[0][0]).toBe(result); - }); - - it('should create traefik router with wildcard in redis', async () => { - mockGraphQLClient.request.mockResolvedValueOnce({ mobilizations: [] }); - - const certificatesController = new CertificatesController(mockGraphQLClient); - await certificatesController.create(request, response); - - const tRouterName = `${request.body.event.data.new.id}-${request.body.event.data.new.domain_name.replace('.', '-')}`; - - expect(mockCreateWildcard.mock.calls[0]).toEqual([tRouterName, request.body.event.data.new.domain_name]) - }); - - it('should call fetchMobilizationsByDomain', async () => { - const certificatesController = new CertificatesController(mockGraphQLClient); - await certificatesController.create(request, response); - - expect(mockGraphQLClient.request.mock.calls[0][0].variables).toEqual({ - domainName: `%${dns.domain_name}%` - }); - }); - - it('should create traefik routers for subdomains in redis', async () => { - const mobilizations = [ - { id: 1, community_id: 2, custom_domain: `www.campaign0.${dns.domain_name}` }, - { id: 2, community_id: 2, custom_domain: `www.campaign1.${dns.domain_name}` } - ] - - mockGraphQLClient.request.mockResolvedValue({ mobilizations }); - - const certificatesController = new CertificatesController(mockGraphQLClient); - await certificatesController.create(request, response); - const routerName = `${request.body.event.data.new.id}-${request.body.event.data.new.domain_name.replace('.', '-')}-www`; - - expect(mockCreateRouters.mock.calls[0]) - .toEqual([routerName, mobilizations.map(m => m.custom_domain)]) - }); - - it('should create only traefik routers for external domain in redis', async () => { - const mobilizations = [ - { id: 1, community_id: 1, custom_domain: `www.${dns.domain_name}` } - ] - - mockGraphQLClient.request.mockResolvedValue({ mobilizations }); - - const certificatesController = new CertificatesController(mockGraphQLClient); - await certificatesController.create({ - body: { - event: { - data: { - new: { - ...dns, - is_external_domain: true - } - } - } - } - }, response); - const routerName = `${request.body.event.data.new.id}-${request.body.event.data.new.domain_name.replace('.', '-')}-external`; - - expect(mockCreateRouters.mock.calls[0]) - .toEqual([routerName, [...mobilizations.map(m => m.custom_domain), dns.domain_name]]) - }); - - // it('should update certificate method', async () => { - // const certificate = { id: 2, domain: 'nossas.tec.br', dns_hosted_zone_id: 23 }; - // mockGraphQLClient.request.mockResolvedValueOnce({ data: { certificate } }); - // const mobilizations = [ - // { id: 1, community_id: 1, custom_domain: `www.sudomain.nossas.tec.br` } - // ] - // mockGraphQLClient.request.mockResolvedValueOnce({ mobilizations }); - - // const certificatesController = new CertificatesController(mockGraphQLClient); - // await certificatesController.update({ body: { input: { id: certificate.id } } }, { json: jest.fn(), status: () => ({ json: jest.fn() }) }); - - // expect(mockGraphQLClient.request.mock.calls.length).toEqual(certificate.id); - // expect(mockGraphQLClient.request.mock.calls[0][0].variables).toEqual({ id: certificate.id }); - // expect(mockGraphQLClient.request.mock.calls[1][0].variables).toEqual({ domainName: `%${certificate.domain}%` }); - - // const tRouterName = `${certificate.dns_hosted_zone_id}-${certificate.domain.replace('.', '-')}`; - // expect(mockCreateWildcard.mock.calls[0]).toEqual([tRouterName, certificate.domain]); - - // const routerName = `${certificate.dns_hosted_zone_id}-${certificate.domain.replace('.', '-')}-www`; - // expect(mockCreateRouters.mock.calls[0]) - // .toEqual([routerName, mobilizations.map(m => m.custom_domain)]); - // }); - }); - - describe('create_or_update_certificate', () => { - // Mock input - let certificatesController; - const actionInput: any = { - body: { - input: { dns_hosted_zone_id: 524 } - } - } - const mockJson = jest.fn(); - const mockRes = { - status: jest.fn().mockImplementation(() => ({ - json: mockJson - })) - } - - beforeEach(() => { - certificatesController = new CertificatesController(mockGraphQLClient); - }); - - it('should search domain with propagated status', async () => { - await certificatesController.create_or_update(actionInput); - expect(mockGraphQLClient.request.mock.calls[0][0]).toEqual({ - document: get_domain, - variables: { id: actionInput.body.input.dns_hosted_zone_id } - }); - }); - - it('should return errors when domain not found', async () => { - mockGraphQLClient.request.mockReturnValueOnce({ dns_hosted_zones_by_pk: null }) - await certificatesController.create_or_update(actionInput, mockRes); - - expect(mockRes.status.mock.calls[0][0]).toEqual(400); - expect(mockJson.mock.calls[0][0]).toEqual({ message: 'domain_not_found' }); - }); - - it('should return errors when domain is not propagated', async () => { - mockGraphQLClient.request.mockReturnValueOnce({ dns_hosted_zones_by_pk: { ns_ok: false } }) - await certificatesController.create_or_update(actionInput, mockRes); - - expect(mockRes.status.mock.calls[0][0]).toEqual(400); - expect(mockJson.mock.calls[0][0]).toEqual({ message: 'domain_not_propagated' }); - }); - - it('should fetch traefik routers when domain is valid', async () => { - mockGraphQLClient.request.mockReturnValueOnce({ - dns_hosted_zones_by_pk: { - id: 587, - domain_name: 'nossas.tec.br', - ns_ok: true, - certificates: [ - { id: 3, domain: 'nossas.tec.br', is_active: true } - ] - } - }); - - await certificatesController.create_or_update(actionInput, mockRes); - expect(mockGetRouters.mock.calls[0]).toEqual([587, 'nossas.tec.br']); - }); - - it('should call createRouters when mobilizations custom domain not exists', async () => { - mockGraphQLClient.request.mockReturnValueOnce({ - dns_hosted_zones_by_pk: { - id: 587, - domain_name: 'nossas.tec.br', - ns_ok: true, - certificates: [ - { id: 3, domain: 'nossas.tec.br', is_active: true } - ] - } - }); - mockGraphQLClient.request.mockReturnValueOnce({ - mobilizations: [ - { id: 123, custom_domain: 'www.other1.nossas.tec.br' }, - { id: 124, custom_domain: 'www.other2.nossas.tec.br' }, - { id: 125, custom_domain: 'www.other3.nossas.tec.br' } - ] - }); - - mockGetRouters.mockResolvedValueOnce(['nossas.tec.br', ['www.other1.nossas.tec.br', 'www.other2.nossas.tec.br']]); - - await certificatesController.create_or_update(actionInput, mockRes); - expect(mockCreateRouters.mock.calls[0]).toEqual( - [`587-nossas-tec-br-www`, ['www.other1.nossas.tec.br', 'www.other2.nossas.tec.br', 'www.other3.nossas.tec.br']] - ); - }); - - it('should call createRouters only subdomains', async () => { - mockGraphQLClient.request.mockReturnValueOnce({ - dns_hosted_zones_by_pk: { - id: 587, - domain_name: 'nossas.tec.br', - ns_ok: true, - certificates: [ - { id: 3, domain: 'nossas.tec.br', is_active: true } - ] - } - }); - mockGraphQLClient.request.mockReturnValueOnce({ - mobilizations: [ - { id: 122, custom_domain: 'www.nossas.tec.br' }, - { id: 123, custom_domain: 'www.other1.nossas.tec.br' }, - { id: 124, custom_domain: 'www.other2.nossas.tec.br' }, - { id: 125, custom_domain: 'www.other3.nossas.tec.br' } - ] - }); - - mockGetRouters.mockResolvedValueOnce(['nossas.tec.br', ['www.other1.nossas.tec.br', 'www.other2.nossas.tec.br']]); - - await certificatesController.create_or_update(actionInput, mockRes); - expect(mockCreateRouters.mock.calls[0]).toEqual( - [`587-nossas-tec-br-www`, ['www.other1.nossas.tec.br', 'www.other2.nossas.tec.br', 'www.other3.nossas.tec.br']] - ); - }); - - it('should not call createRouters when mobilizations custom domain is settings', async () => { - mockGraphQLClient.request.mockReturnValueOnce({ - dns_hosted_zones_by_pk: { - id: 587, - domain_name: 'nossas.tec.br', - ns_ok: true, - certificates: [ - { id: 3, domain: 'nossas.tec.br', is_active: true } - ] - } - }); - mockGraphQLClient.request.mockReturnValueOnce({ - mobilizations: [ - { id: 124, custom_domain: 'www.other2.nossas.tec.br' }, - { id: 125, custom_domain: 'www.other3.nossas.tec.br' }, - { id: 123, custom_domain: 'www.other1.nossas.tec.br' } - ] - }); - - mockGetRouters.mockResolvedValueOnce(['nossas.tec.br', ['www.other3.nossas.tec.br', 'www.other1.nossas.tec.br', 'www.other2.nossas.tec.br']]); - - await certificatesController.create_or_update(actionInput, mockRes); - expect(mockCreateRouters.mock.calls.length).toEqual(0); - }); - - it('should call create when certificates not find', async () => { - jest.spyOn(certificatesController, 'create'); - - mockGraphQLClient.request.mockReturnValueOnce({ - dns_hosted_zones_by_pk: { - id: 587, - domain_name: 'nossas.tec.br', - ns_ok: true, - certificates: [] - } - }); - - await certificatesController.create_or_update(actionInput, mockRes); - expect(certificatesController.create.mock.calls.length).toEqual(1); - expect(certificatesController.create.mock.calls[0][0]).toEqual({ - body: { - event: { - data: { - new: { - id: 587, - domain_name: 'nossas.tec.br', - ns_ok: true, - certificates: [] - } - } - } - } - }); - }); - - it('should call createWildcard when wildcard not found', async () => { - mockGraphQLClient.request.mockReturnValueOnce({ - dns_hosted_zones_by_pk: { - id: 587, - domain_name: 'nossas.tec.br', - ns_ok: true, - certificates: [ - { id: 3, domain: 'nossas.tec.br', is_active: true } - ] - } - }); - mockGraphQLClient.request.mockReturnValueOnce({ - mobilizations: [ - { id: 124, custom_domain: 'www.other2.nossas.tec.br' }, - { id: 125, custom_domain: 'www.other3.nossas.tec.br' }, - { id: 123, custom_domain: 'www.other1.nossas.tec.br' } - ] - }); - - mockGetRouters.mockResolvedValueOnce([undefined, []]); - - await certificatesController.create_or_update(actionInput, mockRes); - expect(mockCreateWildcard.mock.calls.length).toEqual(1); - expect(mockCreateRouters.mock.calls.length).toEqual(1); - }); - }); - - describe('certificate is not create', () => { - // Mock de entradas da função (Padrão para testes que não criam certificado) - const request: any = { - body: { - event: { - data: { - new: { - id: 4, - community_id: 1, - domain_name: 'test.org', - ns_ok: false - } - } - } - } - } - const mockJson = jest.fn(); - const response: any = { - status: jest.fn().mockImplementation(() => ({ - json: mockJson - })) - } - - it('should return 400 when dns is not ok', async () => { - const certificatesController = new CertificatesController(mockGraphQLClient); - await certificatesController.create(request, response); - - expect(response.status.mock.calls[0][0]).toEqual(402); - expect(mockJson.mock.calls[0][0]).toEqual({ message: 'Certificate not created because ns_ok is false.' }); - }); - }); -}) - diff --git a/packages/domains-api/src/controllers/certificates-controller.ts b/packages/domains-api/src/controllers/certificates-controller.ts deleted file mode 100644 index 9438cd10..00000000 --- a/packages/domains-api/src/controllers/certificates-controller.ts +++ /dev/null @@ -1,299 +0,0 @@ -/* eslint-disable @typescript-eslint/explicit-module-boundary-types */ -import logger from '../config/logger'; -import { gql } from '../graphql-api/client'; -import { createRouters, createWildcard, getRouters } from '../etcd-db/certificates'; -import { HasuraActionRequest } from '../types'; -import { validationResult, check } from 'express-validator'; -import sslChecker from "ssl-checker"; - -export interface Request { - body: { - event: { - data: { - new: T - } - } - } -} - -export interface CertificateTLS { - id: number; - dns_hosted_zone_id: number; - is_active: boolean; - community_id: number; - domain: string; - ssl_checker_response?: any; -} - -export interface DNSHostedZone { - id: number; - community_id: number; - domain_name: string; - is_external_domain: boolean; - ns_ok?: boolean; -} - -export interface Mobilization { - id: number; - custom_domain: string; - community_id: number; -} - -interface InputCertificate { - dns_hosted_zone_id: number; -} - -const insert_certificate = gql`mutation ($input: certificates_insert_input!) { - insert_certificates_one(object:$input) { - id - dns_hosted_zone_id - is_active - community_id - domain - ssl_checker_response - } -} -`; - -const update_certificate = gql` -mutation ($id: Int!, $ssl_checker_response: jsonb) { - update_certificates_by_pk(pk_columns: { id: $id }, _set: { is_active: true, ssl_checker_response: $ssl_checker_response }) { - id - dns_hosted_zone_id - is_active - community_id - domain - ssl_checker_response - } -} -`; - -export const fetch_mobilizations_by_domain = gql` - query ($domainName: String) { - mobilizations (where:{ custom_domain:{ _ilike: $domainName } }) { - id - custom_domain - community_id - } - } -`; - -export const get_cerificate = gql` - query ($id: Int!) { - certificate: certificates_by_pk(id: $id) { - id - domain - is_active - dns_hosted_zone_id - } - } -` - -export const get_domain = gql` - query ($id: Int!) { - dns_hosted_zones_by_pk(id: $id) { - id - domain_name - is_external_domain - ns_ok - certificates { - id - domain - created_at - is_active - dns_hosted_zone_id - } - } - } -` - -class CertificatesController { - private graphqlClient: any; - - constructor(graphqlClient) { - this.graphqlClient = graphqlClient; - } - - create = async (req: Request, res) => { - if (!req.body.event) { - await check('event').isObject().run(req); - const errors = validationResult(req); - if (!errors.isEmpty()) { - return res.status(400).json({ errors: errors.array() }); - } - } - - const dns_hosted_zone = req.body.event.data.new; - - if (dns_hosted_zone.ns_ok) { - try { - const domains: string[] = await this.fetchCustomDomains(dns_hosted_zone.domain_name); - await this.insertCertificateRedis(dns_hosted_zone, domains); - res.status(200).json(await this.insertCertificateGraphql(dns_hosted_zone)); - } catch (e: any) { - logger.info(e) - res.status(500).json({ ok: false, ...e }); - } - } else { - res.status(402).json({ message: 'Certificate not created because ns_ok is false.' }); - } - } - - private insertCertificateRedis = async (input: DNSHostedZone, domains: string[]) => { - const { domain_name, id: dns_hosted_zone_id, is_external_domain } = input; - const tRouterName = `${dns_hosted_zone_id}-${domain_name.replace(/\./g, '-')}` - logger.info(`In controller - createCertificate ${tRouterName}`); - - if (!is_external_domain) { - await createWildcard(tRouterName, domain_name); - await createRouters(`${tRouterName}-www`, domains); - } else { - await createRouters(`${tRouterName}-external`, domains.length > 0 ? [...domains, domain_name] : [`www.${domain_name}`, domain_name]); - } - } - - private insertCertificateGraphql = async (input: any): Promise => { - const { domain_name: domain, community_id, id: dns_hosted_zone_id } = input; - const data: any = await this.graphqlClient.request({ - document: insert_certificate, - variables: { input: { domain, community_id, dns_hosted_zone_id, is_active: false } } - }); - - logger.child({ data }).info('insert_certificate.upsert'); - - return data.insert_certificates_one; - } - - private updateCertificateGraphql = async (id: number, ssl_checker_response: any) => { - const data = await this.graphqlClient.request({ - document: update_certificate, - variables: { id, ssl_checker_response } - }); - - logger.child({ data }).info('update_certificates'); - - return data.update_certificates_by_pk; - } - - private fetchCustomDomains = async (domain: string): Promise => { - const data: { mobilizations: Mobilization[] } = await this.graphqlClient.request({ - document: fetch_mobilizations_by_domain, - variables: { domainName: `%${domain}%` } - }); - - logger.child({ data }).info('fetch_mobilizations_by_domain'); - - return data.mobilizations.filter((mob) => mob.custom_domain !== `www.${domain}`).map((mob) => mob.custom_domain); - } - - check = async (req: Request, res) => { - /** - * Esse evento deve ser chamado sempre que criar um novo certificado - * Hasura irá fazer uma nova chamada em caso de erro no intervalo de 6 minutos - * durante 20 tentativas - */ - try { - await check('event').isObject().run(req); - const errors = validationResult(req); - if (!errors.isEmpty()) { - return res.status(400).json({ errors: errors.array() }); - } - - const certificate = req.body.event.data.new; - logger.info(certificate); - - const checker = await sslChecker(certificate.domain); - logger.info(checker); - - if (checker.valid) { - res.json(await this.updateCertificateGraphql(certificate.id, checker)); - } else { - res.status(400).json({ errors: ['invalid_ssl_checker'] }); - } - } catch (e: any) { - logger.info(e) - res.status(500).json({ ok: false, ...e }); - } - } - - private getCertificate = async (dns_hosted_zone_id: number): Promise<{ id: number, domain: string, is_active: boolean, dns_hosted_zone_id: number }> => { - const data = await this.graphqlClient.request({ - document: get_cerificate, - variables: { id: dns_hosted_zone_id } - }); - - if (!data?.certificate) throw new Error('certificate not found'); - - logger.child({ data }).info('get_cerificate'); - - return data.certificate; - } - - update = async (req: HasuraActionRequest, res: any) => { - try { - const certificate = await this.getCertificate(req.body.input.dns_hosted_zone_id); - const domains = await this.fetchCustomDomains(certificate.domain) - - const tRouterName = `${certificate.dns_hosted_zone_id}-${certificate.domain.replace(/\./g, '-')}` - - await createWildcard(tRouterName, certificate.domain); - await createRouters(`${tRouterName}-www`, domains); - - res.json(certificate); - } catch (e: any) { - logger.info(e) - res.status(400).json({ message: e.message }); - } - } - - create_or_update = async (req: HasuraActionRequest, res?: any) => { - try { - const data = await this.graphqlClient.request({ - document: get_domain, - variables: { id: req.body.input.dns_hosted_zone_id } - }); - - const hostedZone = data?.dns_hosted_zones_by_pk; - - if (!hostedZone) throw new Error('domain_not_found'); - if (!hostedZone.ns_ok) throw new Error('domain_not_propagated'); - - if (hostedZone.certificates.length === 0) { - const req: any = { - body: { - event: { - data: { - new: hostedZone - } - } - } - }; - return await this.create(req, res); - } - - const [wildcard, routers] = await getRouters(data.dns_hosted_zones_by_pk.id, data.dns_hosted_zones_by_pk.domain_name); - const customDomains = await this.fetchCustomDomains(data.dns_hosted_zones_by_pk.domain_name); - - const tRouterName = `${hostedZone.id}-${hostedZone.domain_name.replace(/\./g, '-')}`; - if (!wildcard) { - logger.child({ routerName: tRouterName }).info('create_or_update#createWildcard'); - await createWildcard(tRouterName, hostedZone.domain_name); - } - if (JSON.stringify(routers.sort()) !== JSON.stringify(customDomains.sort())) { - logger.child({ - routerName: tRouterName, - routers: JSON.stringify(routers.sort()), - customDomain: JSON.stringify(customDomains.sort()) - }).info('create_or_update#createRouters'); - await createRouters(`${tRouterName}-www`, customDomains); - } - - res?.json(hostedZone.certificates[0]); - } catch (e: any) { - logger.info(e); - res?.status(400).json({ message: e.message }); - } - } -} - -export default CertificatesController; \ No newline at end of file diff --git a/packages/domains-api/src/etcd-db/certificates.spec.ts b/packages/domains-api/src/etcd-db/certificates.spec.ts deleted file mode 100644 index d5258694..00000000 --- a/packages/domains-api/src/etcd-db/certificates.spec.ts +++ /dev/null @@ -1,173 +0,0 @@ -// 1. Criar um rota wildcard para o dominio principal subdomain / domain - Ex.: *.meurio.org.br meurio.org.br, auxiliomoradia.meurio.org.br -// -// 2. Criar uma rota para cada X subdominios com www - Ex.: www.auxiliomoradia.meurio.org.br, www.forapaes.meurio.org.br -// X = 100 - -const mockValue = jest.fn(); -const mockPut = jest.fn().mockImplementation(() => ({ - value: mockValue -})); - -const mockGet = jest.fn().mockImplementation(() => ({ - string: mockValue -})) - -const mockPrefix = jest.fn().mockImplementation(() => ({ - strings: mockValue.mockImplementation(() => []) -})) -const mockGetAll = jest.fn().mockImplementation(() => ({ - prefix: mockPrefix -})) - -jest.mock('./client', () => ({ - put: mockPut, - get: mockGet, - getAll: mockGetAll -})) - -import { DNSHostedZone } from "../controllers/certificates-controller"; -import { createWildcard, createRouters, getRouters } from "./certificates"; - -describe('Certificates Redis', () => { - const dns: DNSHostedZone = { - id: 1, - community_id: 75, - domain_name: 'nossas.tec.br', - is_external_domain: false - }; - - beforeEach(() => { - jest.clearAllMocks(); - }); - - describe('createWildcard is successfully', () => { - const routerName = `${dns.id}-${dns.domain_name.replace('.', '-')}`; - - it('should register wildcard in redis', async () => { - await createWildcard(routerName, dns.domain_name); - - expect(mockPut.mock.calls[0][0]).toEqual(`traefik/http/routers/${routerName}/tls`); - expect(mockValue.mock.calls[0][0]).toEqual('true') - - expect(mockPut.mock.calls[1][0]).toEqual(`traefik/http/routers/${routerName}/tls/certresolver`); - expect(mockValue.mock.calls[1][0]).toEqual('myresolver') - - expect(mockPut.mock.calls[2][0]).toEqual(`traefik/http/routers/${routerName}/rule`); - expect(mockValue.mock.calls[2][0]).toEqual(`HostRegexp(\`${dns.domain_name}\`, \`{subdomain:.+}.${dns.domain_name}\`)`) - - expect(mockPut.mock.calls[3][0]).toEqual(`traefik/http/routers/${routerName}/tls/domains/0/main`); - expect(mockValue.mock.calls[3][0]).toEqual(dns.domain_name) - - expect(mockPut.mock.calls[4][0]).toEqual(`traefik/http/routers/${routerName}/tls/domains/0/sans/0`); - expect(mockValue.mock.calls[4][0]).toEqual(`*.${dns.domain_name}`) - - expect(mockPut.mock.calls[5][0]).toEqual(`traefik/http/routers/${routerName}/service`); - expect(mockValue.mock.calls[5][0]).toEqual('public@docker') - }); - }); - - describe('getRouters', () => { - it('should call get main configuration to domain', async () => { - mockValue.mockReturnValueOnce('nossas.link'); - - await getRouters(587, 'nossas.link'); - expect(mockGet.mock.calls[0][0]).toEqual('traefik/http/routers/587-nossas-link/tls/domains/0/main'); - }); - - it('should call get subrouters configuration to domain', async () => { - mockValue.mockReturnValueOnce('nossas.link'); - mockValue.mockReturnValueOnce({ - "traefik/http/routers/587-nossas-link-www-0/rule": "Host(`www.other1.nossas.link`, `www.other2.nossas.link`)", - "traefik/http/routers/587-nossas-link-www-0/service": "public@docker", - "traefik/http/routers/587-nossas-link-www-0/tls": "true", - "traefik/http/routers/587-nossas-link-www-0/tls/certresolver": "myresolver" - }) - - await getRouters(587, 'nossas.link'); - const routerName = `587-nossas-link`; - expect(mockGetAll.mock.calls.length).toEqual(1); - expect(mockPrefix.mock.calls[0][0]).toEqual(`traefik/http/routers/${routerName}-www`); - }); - - it('should return all routers configuration to domain', async () => { - mockValue.mockReturnValueOnce('nossas.link'); - mockValue.mockReturnValueOnce({ - "traefik/http/routers/587-nossas-link-www-0/rule": "Host(`www.other1.nossas.link`, `www.other2.nossas.link`)", - "traefik/http/routers/587-nossas-link-www-0/service": "public@docker", - "traefik/http/routers/587-nossas-link-www-0/tls": "true", - "traefik/http/routers/587-nossas-link-www-0/tls/certresolver": "myresolver" - }) - - const [wildcard, routers] = await getRouters(587, 'nossas.link'); - expect(wildcard).toEqual('nossas.link'); - expect(routers).toEqual(['www.other1.nossas.link', 'www.other2.nossas.link']); - }); - - it('should return wildcard undefined when not configuration', async () => { - mockValue.mockReturnValueOnce(undefined); - mockValue.mockReturnValueOnce([]) - - const [wildcard, routers] = await getRouters(587, 'nossas.link'); - expect(wildcard).toEqual(undefined); - expect(routers).toEqual([]); - }); - }); - - describe('createRouters is successfully', () => { - const routerName = `${dns.id}-${dns.domain_name.replace('.', '-')}-www`; - const domainNames = [ - `www.campanha1.${dns.domain_name}`, - `www.campanha2.${dns.domain_name}`, - `www.campanha3.${dns.domain_name}` - ] - - it('should register in redis a router with domainNames', async () => { - await createRouters(routerName, domainNames); - - expect(mockPut.mock.calls[0][0]).toEqual(`traefik/http/routers/${routerName}-0/tls`); - expect(mockValue.mock.calls[0][0]).toEqual('true'); - - expect(mockPut.mock.calls[1][0]).toEqual(`traefik/http/routers/${routerName}-0/tls/certresolver`); - expect(mockValue.mock.calls[1][0]).toEqual('myresolver'); - - expect(mockPut.mock.calls[2][0]).toEqual(`traefik/http/routers/${routerName}-0/service`); - expect(mockValue.mock.calls[2][0]).toEqual('public@docker'); - - expect(mockPut.mock.calls[3][0]).toEqual(`traefik/http/routers/${routerName}-0/rule`); - expect(mockValue.mock.calls[3][0]).toEqual(`Host(${domainNames.map((domain) => `\`${domain}\``).join(',')})`); - }); - - it('should register in redis a router every 100 domainNames', async () => { - const manyDomainNames = Array.from({ length: 150 }, (_, index: number) => `www.campanha${index}.${dns.domain_name}`); - - await createRouters(routerName, manyDomainNames); - - expect(mockPut.mock.calls[0][0]).toEqual(`traefik/http/routers/${routerName}-0/tls`); - expect(mockValue.mock.calls[0][0]).toEqual('true') - expect(mockPut.mock.calls[1][0]).toEqual(`traefik/http/routers/${routerName}-1/tls`); - expect(mockValue.mock.calls[1][0]).toEqual('true') - - expect(mockPut.mock.calls[2][0]).toEqual(`traefik/http/routers/${routerName}-0/tls/certresolver`); - expect(mockValue.mock.calls[2][0]).toEqual('myresolver') - expect(mockPut.mock.calls[3][0]).toEqual(`traefik/http/routers/${routerName}-1/tls/certresolver`); - expect(mockValue.mock.calls[3][0]).toEqual('myresolver') - - expect(mockPut.mock.calls[4][0]).toEqual(`traefik/http/routers/${routerName}-0/service`); - expect(mockValue.mock.calls[4][0]).toEqual('public@docker') - expect(mockPut.mock.calls[5][0]).toEqual(`traefik/http/routers/${routerName}-1/service`); - expect(mockValue.mock.calls[5][0]).toEqual('public@docker') - - expect(mockPut.mock.calls[6][0]).toEqual(`traefik/http/routers/${routerName}-0/rule`); - expect(mockValue.mock.calls[6][0]).toEqual(`Host(${manyDomainNames.slice(0, 100).map((domain) => `\`${domain}\``).join(',')})`) - expect(mockPut.mock.calls[7][0]).toEqual(`traefik/http/routers/${routerName}-1/rule`); - expect(mockValue.mock.calls[7][0]).toEqual(`Host(${manyDomainNames.slice(100, 150).map((domain) => `\`${domain}\``).join(',')})`) - }); - - it('should not call configuration if domains is empty', async () => { - await createRouters('qualquer-nome', []); - - expect(mockPut.mock.calls.length).toEqual(0); - expect(mockValue.mock.calls.length).toEqual(0); - }); - }); -}); \ No newline at end of file diff --git a/packages/domains-api/src/etcd-db/certificates.ts b/packages/domains-api/src/etcd-db/certificates.ts deleted file mode 100644 index 981ac322..00000000 --- a/packages/domains-api/src/etcd-db/certificates.ts +++ /dev/null @@ -1,59 +0,0 @@ -import logger from '../config/logger'; -import etcdClient from './client'; - -export const createWildcard = async (routerName: string, domainName: string): Promise => { - // Configure routers - await etcdClient.put(`traefik/http/routers/${routerName}/tls`).value('true'); - await etcdClient.put(`traefik/http/routers/${routerName}/tls/certresolver`).value('myresolver'); - await etcdClient.put(`traefik/http/routers/${routerName}/rule`).value(`HostRegexp(\`${domainName}\`, \`{subdomain:.+}.${domainName}\`)`); - await etcdClient.put(`traefik/http/routers/${routerName}/tls/domains/0/main`).value(domainName); - await etcdClient.put(`traefik/http/routers/${routerName}/tls/domains/0/sans/0`).value(`*.${domainName}`); - await etcdClient.put(`traefik/http/routers/${routerName}/service`).value('public@docker'); - - logger.child({ routerName, domainName }).info('createWildcard'); -} - -export const createRouters = async (routerName: string, domainNames: string[]): Promise => { - // Configure routers - if (domainNames.length !== 0) { - let cursor = Math.floor(domainNames.length / 100); - if (domainNames.length % 100 !== 0) cursor += 1; - - await Promise.all(Array.from({ length: cursor > 0 ? cursor : 1 }, async (_, index: number) => { - await etcdClient.put(`traefik/http/routers/${routerName}-${index}/tls`).value('true'); - await etcdClient.put(`traefik/http/routers/${routerName}-${index}/tls/certresolver`).value('myresolver'); - await etcdClient.put(`traefik/http/routers/${routerName}-${index}/service`).value('public@docker'); - await etcdClient - .put(`traefik/http/routers/${routerName}-${index}/rule`) - .value( - `Host(${domainNames.slice(index * 100, (index + 1) * 100).map((domain) => `\`${domain}\``).join(',')})` - ); - })) - } - logger.child({ routerName, domainNames }).info('createRouters'); -} - -export const getRouters = async (id: number, domain: string): Promise<[string | null, string[]]> => { - const routerName = `${id}-${domain.replace(/\./g, '-')}`; - - const value = await etcdClient.get(`traefik/http/routers/${routerName}/tls/domains/0/main`).string(); - - const values: any = Object.values(await etcdClient.getAll().prefix(`traefik/http/routers/${routerName}-www`).strings()); - - const res: any = []; - for (let i = 0; i < values.length; i += 4) { - const chunk: string[] = values.slice(i, i + 4); - res.push(chunk); - } - - const routers: any[] = [] - res.forEach(element => { - const elementSplit = element[0].split(',').map((host) => host.match(/`(.+)`/gi)).map( - el => el[0].replace(/`/g, '') - ); - routers.push(...elementSplit); - }); - - logger.child({ routerName, wildcard: value, routers, values }).info('getRouters'); - return [value, routers]; -} \ No newline at end of file diff --git a/packages/domains-api/src/etcd-db/client.ts b/packages/domains-api/src/etcd-db/client.ts deleted file mode 100644 index e4467731..00000000 --- a/packages/domains-api/src/etcd-db/client.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { Etcd3 } from 'etcd3'; - -const client = new Etcd3({ - hosts: process.env.ETCD_URL || 'http://etcd:2379' -}); - -export default client \ No newline at end of file diff --git a/packages/domains-api/src/routes/actions-route.ts b/packages/domains-api/src/routes/actions-route.ts index 56a265ed..18aa4ec1 100644 --- a/packages/domains-api/src/routes/actions-route.ts +++ b/packages/domains-api/src/routes/actions-route.ts @@ -4,19 +4,16 @@ import RecordsController from '../controllers/records-controller'; import DomainsController from '../controllers/domains-controller'; import * as DNSHostedZonesAPI from '../graphql-api/dns_hosted_zones'; import { client } from '../graphql-api/client'; -import CertificatesController from '../controllers/certificates-controller'; const router = express.Router(); const recordsController = new RecordsController(DNSHostedZonesAPI, client); const domainsController = new DomainsController(DNSHostedZonesAPI, client); -const certificatesController = new CertificatesController(client); // define routes router.post('/create-domain', domainsController.createDomains); router.post('/delete-domain', domainsController.deleteDomains); router.post('/create-record', recordsController.createRecords); router.post('/delete-record', recordsController.deleteRecords); -router.post('/create-or-update-certificate', certificatesController.create_or_update); export default router; diff --git a/packages/domains-api/src/routes/events-route.ts b/packages/domains-api/src/routes/events-route.ts deleted file mode 100644 index e57508cd..00000000 --- a/packages/domains-api/src/routes/events-route.ts +++ /dev/null @@ -1,15 +0,0 @@ -// import dependencies and initialize the express router -import express from 'express'; -import CertificatesController from '../controllers/certificates-controller'; -// import redisClient from '../redis-db/client' -import { client } from '../graphql-api/client'; - -const router = express.Router(); - -const certificatesController = new CertificatesController(client); - -// define routes -router.post('/create-certificate', certificatesController.create); -router.post('/check-certificate', certificatesController.check); - -export default router; \ No newline at end of file diff --git a/packages/domains-api/src/server/app.ts b/packages/domains-api/src/server/app.ts index 88ec5d8b..f8b72c30 100644 --- a/packages/domains-api/src/server/app.ts +++ b/packages/domains-api/src/server/app.ts @@ -14,7 +14,6 @@ import logger from '../config/logger'; import healthRoutes from '../routes/health-route'; import swaggerRoutes from '../routes/swagger-route'; import actionsRoutes from '../routes/actions-route'; -import eventsRoutes from '../routes/events-route'; const app = express(); @@ -35,7 +34,6 @@ app.use(bodyParser.json()); app.use('/health', healthRoutes); app.use('/swagger', swaggerRoutes); app.use('/actions', actionsRoutes); -app.use('/events', eventsRoutes); // async () => { // if (!config.jwtSecret) throw new Error('No JWT_SECRET provided.');