diff --git a/package.json b/package.json index 671064e31..7865e15a7 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "azion-platform-kit", - "version": "1.8.0", + "version": "1.8.1", "private": true, "type": "module", "repository": { diff --git a/src/assets/themes/scss/themes/azion-light/extended-components/_selectbutton.scss b/src/assets/themes/scss/themes/azion-light/extended-components/_selectbutton.scss index 11689874e..117484761 100644 --- a/src/assets/themes/scss/themes/azion-light/extended-components/_selectbutton.scss +++ b/src/assets/themes/scss/themes/azion-light/extended-components/_selectbutton.scss @@ -1,7 +1,7 @@ // Custom SelectButton .p-selectbutton { background: var(--surface-300) !important; - padding-inline: 0.75rem !important; + padding: 0.3rem; border-radius: $borderRadius !important; .p-button { @@ -19,7 +19,6 @@ } &.p-highlight { - padding-inline: 0.75rem !important; background: var(--surface-0) !important; border-color: none !important; font-weight: 600 !important; diff --git a/src/helpers/azion-documentation-catalog.js b/src/helpers/azion-documentation-catalog.js index 38cc1267a..3fd2370df 100644 --- a/src/helpers/azion-documentation-catalog.js +++ b/src/helpers/azion-documentation-catalog.js @@ -28,7 +28,7 @@ export const documentationCatalog = { records: () => openSearchResult('records'), waf: () => openSearchResult('waf'), wafAllowed: () => openSearchResult('Allowed Rules'), - wafTuning: () => openSearchResult('Tuning') + wafTuning: () => openSearchResult('Tune') } export const documentationGuideProducts = { diff --git a/src/router/routes/waf-rules-routes/index.js b/src/router/routes/waf-rules-routes/index.js index fe17e084c..78cbe5a09 100644 --- a/src/router/routes/waf-rules-routes/index.js +++ b/src/router/routes/waf-rules-routes/index.js @@ -1,5 +1,6 @@ import * as Helpers from '@/helpers' import * as WafRulesService from '@/services/waf-rules-services' +import { listCountriesService } from '@/services/network-lists-services' /** @type {import('vue-router').RouteRecordRaw} */ export const wafRulesRoutes = { @@ -55,14 +56,21 @@ export const wafRulesRoutes = { loadWafRulesAllowedService: WafRulesService.loadWafRulesAllowedService, editWafRulesAllowedService: WafRulesService.editWafRulesAllowedService, documentationServiceAllowed: Helpers.documentationCatalog.wafAllowed, - listWafRulesAllowedService: WafRulesService.listWafRulesAllowedService + listWafRulesAllowedService: WafRulesService.listWafRulesAllowedService, + optionsRuleIds: WafRulesService.optionsRuleIds }, wafServices: { editWafRulesService: WafRulesService.editWafRulesService, loadWafRulesService: WafRulesService.loadWafRulesService }, wafTuning: { - documentationServiceTuning: Helpers.documentationCatalog.wafTuning + documentationServiceTuning: Helpers.documentationCatalog.wafTuning, + listWafRulesTuningService: WafRulesService.listWafRulesTuningService, + listNetworkListService: WafRulesService.listNetworkListService, + listCountriesService: listCountriesService, + listWafRulesDomainsService: WafRulesService.listWafRulesDomainsService, + createWafRulesAllowedTuningService: WafRulesService.createWafRulesAllowedTuningService, + listWafRulesTuningAttacksService: WafRulesService.listWafRulesTuningAttacksService } }, meta: { diff --git a/src/services/credential-services/create-credential-service.js b/src/services/credential-services/create-credential-service.js index e3323e298..1d3b15fff 100644 --- a/src/services/credential-services/create-credential-service.js +++ b/src/services/credential-services/create-credential-service.js @@ -69,6 +69,6 @@ const adapt = (payload) => { return { name: payload.name, description: payload.description, - status: true + status: payload.status } } diff --git a/src/services/domains-services/list-domains-service.js b/src/services/domains-services/list-domains-service.js index 6cb639272..0bb4576ae 100644 --- a/src/services/domains-services/list-domains-service.js +++ b/src/services/domains-services/list-domains-service.js @@ -1,5 +1,7 @@ import { AxiosHttpClientAdapter, parseHttpResponse } from '../axios/AxiosHttpClientAdapter' import { makeDomainsBaseUrl } from './make-domains-base-url' +import { listEdgeApplicationsService } from '@/services/edge-application-services/list-edge-applications-service' + export const listDomainsService = async ({ orderBy = 'name', sort = 'asc', @@ -12,12 +14,14 @@ export const listDomainsService = async ({ method: 'GET' }) - httpResponse = adapt(httpResponse) + httpResponse = await adapt(httpResponse) return parseHttpResponse(httpResponse) } -const adapt = (httpResponse) => { +const adapt = async (httpResponse) => { + const edgeApplications = await listEdgeApplications() + const parsedDomains = httpResponse.body.results?.map((domain) => { const cnames = domain.cnames.map((cname) => cname)?.join(',') return { @@ -32,12 +36,13 @@ const adapt = (httpResponse) => { content: 'Inactive', severity: 'danger' }, + activeSort: domain.is_active, domainName: { content: domain.domain_name }, cnames: cnames, edgeFirewallId: domain.edge_firewall_id, - edgeApplicationName: domain.name, + edgeApplicationName: getEdgeApplication(edgeApplications, domain.edge_application_id), digitalCertificateId: domain.digital_certificate_id } }) @@ -57,3 +62,18 @@ const makeSearchParams = ({ orderBy, sort, page, pageSize }) => { return searchParams } + +const listEdgeApplications = async () => { + const edgeApplications = await listEdgeApplicationsService({}) + + return edgeApplications.map((edgeApp) => ({ name: edgeApp.name, id: edgeApp.id })) +} + +const getEdgeApplication = (edgeApplications, edge_application_id) => { + const edgeApplication = edgeApplications.filter((edgeapp) => edgeapp.id === edge_application_id) + + if (edgeApplication.length > 0) { + return edgeApplication[0].name + } + return '' +} diff --git a/src/services/edge-application-functions-services/list-edge-functions-service.js b/src/services/edge-application-functions-services/list-edge-functions-service.js index 7c1d49246..4f7e051b1 100644 --- a/src/services/edge-application-functions-services/list-edge-functions-service.js +++ b/src/services/edge-application-functions-services/list-edge-functions-service.js @@ -22,8 +22,8 @@ const adapt = (httpResponse) => { return { value: edgeFunction.id, label: edgeFunction.name, - args: edgeFunction.json_args, - initiatorType: edgeFunction.initiator_type, + args: JSON.stringify(edgeFunction.json_args, null, '\t'), + initiatorType: edgeFunction.initiator_type } }) diff --git a/src/services/edge-firewall-functions-services/list-edge-functions-service.js b/src/services/edge-firewall-functions-services/list-edge-functions-service.js index 7c1d49246..4f7e051b1 100644 --- a/src/services/edge-firewall-functions-services/list-edge-functions-service.js +++ b/src/services/edge-firewall-functions-services/list-edge-functions-service.js @@ -22,8 +22,8 @@ const adapt = (httpResponse) => { return { value: edgeFunction.id, label: edgeFunction.name, - args: edgeFunction.json_args, - initiatorType: edgeFunction.initiator_type, + args: JSON.stringify(edgeFunction.json_args, null, '\t'), + initiatorType: edgeFunction.initiator_type } }) diff --git a/src/services/waf-rules-services/create-waf-rules-allowed-service.js b/src/services/waf-rules-services/create-waf-rules-allowed-service.js index 64f7c6ddb..2972981f5 100644 --- a/src/services/waf-rules-services/create-waf-rules-allowed-service.js +++ b/src/services/waf-rules-services/create-waf-rules-allowed-service.js @@ -39,7 +39,10 @@ const adapt = (payload) => { const parseHttpResponse = (httpResponse) => { switch (httpResponse.statusCode) { case 202: - return 'Your waf rule allowed has been created' + return { + feedback: 'Your waf rule allowed has been created' + } + case 400: const apiError = extractApiError(httpResponse) throw new Error(apiError).message @@ -62,8 +65,19 @@ const parseHttpResponse = (httpResponse) => { * @returns {string|undefined} The result message based on the status code. */ const extractErrorKey = (errorSchema, key) => { - const [keyError] = Object.keys(errorSchema[key]?.[0]) - return errorSchema[key]?.[0][keyError][0] + if (typeof errorSchema[key][0] === 'string') { + return `${key}: ${errorSchema[key][0]}` + } + const keyValuePair = [] + errorSchema[key].forEach((obj) => { + for (let key in obj) { + // eslint-disable-next-line no-prototype-builtins + if (obj.hasOwnProperty(key)) { + keyValuePair.push({ key, value: obj[key][0] }) + } + } + }) + return `${keyValuePair[0].key}: ${keyValuePair[0].value}` } /** diff --git a/src/services/waf-rules-services/create-waf-rules-allowed-tuning-service.js b/src/services/waf-rules-services/create-waf-rules-allowed-tuning-service.js new file mode 100644 index 000000000..045856054 --- /dev/null +++ b/src/services/waf-rules-services/create-waf-rules-allowed-tuning-service.js @@ -0,0 +1,81 @@ +import { AxiosHttpClientAdapter } from '../axios/AxiosHttpClientAdapter' +import * as Errors from '@/services/axios/errors' +import { makeWafRulesAllowedBaseUrl } from './make-waf-rules-allowed-base-url' + +export const createWafRulesAllowedTuningService = async ({ payload, wafId }) => { + let httpResponse = await AxiosHttpClientAdapter.request({ + url: `${makeWafRulesAllowedBaseUrl()}/${wafId}/allowed_rules`, + method: 'POST', + body: adapt(payload) + }) + + return parseHttpResponse(httpResponse) +} + +const adapt = (payload) => { + return { + rule_id: payload.ruleId, + match_zones: payload.matchZone, + reason: payload.reason + } +} + +/** + * @param {Object} httpResponse - The HTTP response object. + * @param {Object} httpResponse.body - The response body. + * @param {String} httpResponse.statusCode - The HTTP status code. + * @returns {string} The result message based on the status code. + * @throws {Error} If there is an error with the response. + */ +const parseHttpResponse = (httpResponse) => { + switch (httpResponse.statusCode) { + case 202: + return 'Your waf rule allowed has been created' + case 400: + const apiError = extractApiError(httpResponse) + throw new Error(apiError).message + case 401: + throw new Errors.InvalidApiTokenError().message + case 403: + throw new Errors.PermissionError().message + case 404: + throw new Errors.NotFoundError().message + case 500: + throw new Errors.InternalServerError().message + default: + throw new Errors.UnexpectedError().message + } +} + +/** + * @param {Object} errorSchema - The error schema. + * @param {string} key - The error key of error schema. + * @returns {string|undefined} The result message based on the status code. + */ +const extractErrorKey = (errorSchema, key) => { + if (typeof errorSchema[key][0] === 'string') { + return `${key}: ${errorSchema[key][0]}` + } + const keyValuePair = [] + errorSchema[key].forEach((obj) => { + for (let key in obj) { + // eslint-disable-next-line no-prototype-builtins + if (obj.hasOwnProperty(key)) { + keyValuePair.push({ key, value: obj[key][0] }) + } + } + }) + return `${keyValuePair[0].key}: ${keyValuePair[0].value}` +} + +/** + * @param {Object} httpResponse - The HTTP response object. + * @param {Object} httpResponse.body - The response body. + * @returns {string} The result message based on the status code. + */ +const extractApiError = (httpResponse) => { + const [firstKey] = Object.keys(httpResponse.body) + const errorMessage = extractErrorKey(httpResponse.body, firstKey) + + return errorMessage +} diff --git a/src/services/waf-rules-services/delete-waf-rules-allowed-service.js b/src/services/waf-rules-services/delete-waf-rules-allowed-service.js index 6545cf49f..b04a2cc8c 100644 --- a/src/services/waf-rules-services/delete-waf-rules-allowed-service.js +++ b/src/services/waf-rules-services/delete-waf-rules-allowed-service.js @@ -19,7 +19,7 @@ export const deleteWafRulesAllowedService = async ({ wafId, allowedId }) => { */ const parseHttpResponse = (httpResponse) => { switch (httpResponse.statusCode) { - case 200: + case 202: return 'Waf rule allowed successfully deleted' case 400: throw new Errors.NotFoundError().message diff --git a/src/services/waf-rules-services/edit-waf-rules-allowed-service.js b/src/services/waf-rules-services/edit-waf-rules-allowed-service.js index f4416a3a0..faf472213 100644 --- a/src/services/waf-rules-services/edit-waf-rules-allowed-service.js +++ b/src/services/waf-rules-services/edit-waf-rules-allowed-service.js @@ -38,7 +38,7 @@ const adapt = (payload) => { */ const parseHttpResponse = (httpResponse) => { switch (httpResponse.statusCode) { - case 200: + case 202: return 'Your waf rule allowed has been updated' case 400: const apiError = extractApiError(httpResponse) diff --git a/src/services/waf-rules-services/index.js b/src/services/waf-rules-services/index.js index b13c20751..652452a5e 100644 --- a/src/services/waf-rules-services/index.js +++ b/src/services/waf-rules-services/index.js @@ -8,7 +8,12 @@ import { deleteWafRulesAllowedService } from './delete-waf-rules-allowed-service import { createWafRulesAllowedService } from './create-waf-rules-allowed-service' import { loadWafRulesAllowedService } from './load-waf-rules-allowed-service' import { editWafRulesAllowedService } from './edit-waf-rules-allowed-service' - +import { listWafRulesTuningService } from './list-waf-rules-tuning-service' +import { listNetworkListService } from './list-network-list-service' +import { listWafRulesDomainsService } from './list-waf-rules-domain-service' +import { createWafRulesAllowedTuningService } from './create-waf-rules-allowed-tuning-service' +import { listWafRulesTuningAttacksService } from './list-waf-rules-tuning-attacks-service' +import { optionsRuleIds } from './ruleIdOptions' export { listWafRulesService, deleteWafRulesService, @@ -19,5 +24,11 @@ export { deleteWafRulesAllowedService, createWafRulesAllowedService, loadWafRulesAllowedService, - editWafRulesAllowedService + editWafRulesAllowedService, + listWafRulesTuningService, + listNetworkListService, + listWafRulesDomainsService, + createWafRulesAllowedTuningService, + listWafRulesTuningAttacksService, + optionsRuleIds } diff --git a/src/services/waf-rules-services/list-network-list-service.js b/src/services/waf-rules-services/list-network-list-service.js new file mode 100644 index 000000000..d4c09088f --- /dev/null +++ b/src/services/waf-rules-services/list-network-list-service.js @@ -0,0 +1,28 @@ +import { AxiosHttpClientAdapter, parseHttpResponse } from '../axios/AxiosHttpClientAdapter' +import { makeNetworkListBaseUrl } from '../network-lists-services/make-network-list-base-url' + +export const listNetworkListService = async () => { + let httpResponse = await AxiosHttpClientAdapter.request({ + url: `${makeNetworkListBaseUrl()}?pagination=false&exclude_azion_lists=true`, + method: 'GET' + }) + + httpResponse = adapt(httpResponse) + return parseHttpResponse(httpResponse) +} + +const adapt = (httpResponse) => { + const isArray = Array.isArray(httpResponse.body.results) + + const networkList = isArray + ? httpResponse.body.results.map((networkList) => ({ + id: networkList.id, + name: networkList.name + })) + : [] + + return { + body: networkList, + statusCode: httpResponse.statusCode + } +} diff --git a/src/services/waf-rules-services/list-waf-rules-allowed-service.js b/src/services/waf-rules-services/list-waf-rules-allowed-service.js index 7e4b475d2..3715a27b4 100644 --- a/src/services/waf-rules-services/list-waf-rules-allowed-service.js +++ b/src/services/waf-rules-services/list-waf-rules-allowed-service.js @@ -1,9 +1,9 @@ import { AxiosHttpClientAdapter, parseHttpResponse } from '../axios/AxiosHttpClientAdapter' import { makeWafRulesAllowedBaseUrl } from './make-waf-rules-allowed-base-url' - +import { optionsRuleIds } from './ruleIdOptions' export const listWafRulesAllowedService = async ({ wafId }) => { let httpResponse = await AxiosHttpClientAdapter.request({ - url: `${makeWafRulesAllowedBaseUrl()}/${wafId}/allowed_rules?page=1&page_size=100`, + url: `${makeWafRulesAllowedBaseUrl()}/${wafId}/allowed_rules?page=1&page_size=200`, method: 'GET' }) @@ -75,6 +75,7 @@ const adapt = (httpResponse) => { const parsedWafRulesAllowed = isArray ? httpResponse.body.results.map((waf) => { + const ruleId = optionsRuleIds.find((rule) => rule.value === waf.rule_id).text const parsedAllowed = { id: waf.id, lastEditor: waf.last_editor, @@ -84,7 +85,7 @@ const adapt = (httpResponse) => { matchZones: parseMatchZone(waf.match_zones), path: waf.path, reason: waf.reason, - ruleId: waf.rule_id === 0 ? '0 - All Rules' : waf.rule_id, + ruleId, status: parseStatusData(waf.status), useRegex: waf.use_regex } diff --git a/src/services/waf-rules-services/list-waf-rules-domain-service.js b/src/services/waf-rules-services/list-waf-rules-domain-service.js new file mode 100644 index 000000000..b9ad24b71 --- /dev/null +++ b/src/services/waf-rules-services/list-waf-rules-domain-service.js @@ -0,0 +1,37 @@ +import { AxiosHttpClientAdapter, parseHttpResponse } from '../axios/AxiosHttpClientAdapter' +import { makeWafRulesBaseUrl } from './make-waf-rules-base-url' + +export const listWafRulesDomainsService = async ({ wafId }) => { + let httpResponse = await AxiosHttpClientAdapter.request({ + url: `${makeWafRulesBaseUrl()}/${wafId}/domains`, + method: 'GET' + }) + + httpResponse = adapt(httpResponse) + + return parseHttpResponse(httpResponse) +} + +const adapt = (httpResponse) => { + /** + * Necessary until the API gets the common pattern + * of returning the array of data inside results property + * like other andpoints. + */ + + // eslint-disable-next-line no-console + const isArray = Array.isArray(httpResponse.body.results) + + const parsedWafRulesDomain = isArray + ? httpResponse.body.results.map((domain) => ({ + domain: domain.domain, + id: domain.id, + name: domain.name + })) + : [] + + return { + body: parsedWafRulesDomain, + statusCode: httpResponse.statusCode + } +} diff --git a/src/services/waf-rules-services/list-waf-rules-service.js b/src/services/waf-rules-services/list-waf-rules-service.js index 25206afdb..f2bd55916 100644 --- a/src/services/waf-rules-services/list-waf-rules-service.js +++ b/src/services/waf-rules-services/list-waf-rules-service.js @@ -3,7 +3,7 @@ import { makeWafRulesBaseUrl } from './make-waf-rules-base-url' export const listWafRulesService = async () => { let httpResponse = await AxiosHttpClientAdapter.request({ - url: `${makeWafRulesBaseUrl()}/?page=1&page_size=100`, + url: `${makeWafRulesBaseUrl()}/?page=1&page_size=200`, method: 'GET' }) diff --git a/src/services/waf-rules-services/list-waf-rules-tuning-attacks-service.js b/src/services/waf-rules-services/list-waf-rules-tuning-attacks-service.js new file mode 100644 index 000000000..da1792991 --- /dev/null +++ b/src/services/waf-rules-services/list-waf-rules-tuning-attacks-service.js @@ -0,0 +1,50 @@ +import { AxiosHttpClientAdapter, parseHttpResponse } from '../axios/AxiosHttpClientAdapter' +import { makeWafRulesBaseUrl } from './make-waf-rules-base-url' + +export const listWafRulesTuningAttacksService = async ({ wafId, tuningId, query }) => { + let httpResponse = await AxiosHttpClientAdapter.request({ + url: `${makeWafRulesBaseUrl()}/${wafId}/waf_events/${tuningId}${query}`, + method: 'GET' + }) + + httpResponse = adapt(httpResponse) + + return parseHttpResponse(httpResponse) +} + +const adapt = (httpResponse) => { + /** + * Necessary until the API gets the common pattern + * of returning the array of data inside results property + * like other andpoints. + */ + + // eslint-disable-next-line no-console + const isArray = Array.isArray(httpResponse.body.results) + + const parsedWafRulesTuning = isArray + ? httpResponse.body.results.map((event, index) => { + const values = { + hitCount: event.hit_count, + topIps: event.top_10_ips.map((ip) => ip.ip), + id: index, + ruleId: event.rule_id, + ipCount: event.ip_count, + matchZone: event.match_zone, + pathCount: event.path_count, + topCountries: event.top_10_countries.map((country) => country.country), + matchesOn: event.matches_on, + countryCount: event.country_count, + topPaths: event.top_10_paths.map((path) => path.path), + matchValue: event.match_value + } + + return values + }) + : [] + + return { + body: parsedWafRulesTuning, + statusCode: httpResponse.statusCode + } +} diff --git a/src/services/waf-rules-services/list-waf-rules-tuning-service.js b/src/services/waf-rules-services/list-waf-rules-tuning-service.js new file mode 100644 index 000000000..49775d92b --- /dev/null +++ b/src/services/waf-rules-services/list-waf-rules-tuning-service.js @@ -0,0 +1,49 @@ +import { AxiosHttpClientAdapter, parseHttpResponse } from '../axios/AxiosHttpClientAdapter' +import { makeWafRulesBaseUrl } from './make-waf-rules-base-url' + +export const listWafRulesTuningService = async ({ wafId, query }) => { + let httpResponse = await AxiosHttpClientAdapter.request({ + url: `${makeWafRulesBaseUrl()}/${wafId}/waf_events${query}`, + method: 'GET' + }) + + httpResponse = adapt(httpResponse) + + return parseHttpResponse(httpResponse) +} + +const adapt = (httpResponse) => { + /** + * Necessary until the API gets the common pattern + * of returning the array of data inside results property + * like other andpoints. + */ + + // eslint-disable-next-line no-console + const isArray = Array.isArray(httpResponse.body.results) + + const parsedWafRulesTuning = isArray + ? httpResponse.body.results.map((event) => { + const values = { + hitCount: event.hit_count, + topIps: event.top_10_ips[0][1], + id: event.rule_id, + ruleIdDescription: `${event.rule_id} - ${event.rule_description}`, + ipCount: event.ip_count, + matchZone: event.match_zone, + pathCount: event.path_count, + topCountries: event.top_10_countries[0][1], + matchesOn: event.matches_on, + ruleDescription: event.rule_description, + countryCount: event.country_count + } + + return values + }) + : [] + + return { + body: parsedWafRulesTuning, + statusCode: httpResponse.statusCode + } +} diff --git a/src/services/waf-rules-services/ruleIdOptions.js b/src/services/waf-rules-services/ruleIdOptions.js new file mode 100644 index 000000000..87c43d395 --- /dev/null +++ b/src/services/waf-rules-services/ruleIdOptions.js @@ -0,0 +1,225 @@ +/* eslint-disable no-useless-escape */ + +export const optionsRuleIds = [ + { value: 0, text: '0 - All Rules' }, + { value: 1, text: '1 - Validation of protocol compliance: weird request, unable to parse' }, + { value: 2, text: '2 - Request too big, stored on disk and not parsed' }, + { value: 10, text: '10 - Validation of protocol compliance: invalid HEX encoding (null bytes)' }, + { + value: 11, + text: '11 - Validation of protocol compliance: missing or unknown Content-Type header in a POST (this rule applies only to Request Body match zone)' + }, + { value: 12, text: '12 - Validation of protocol compliance: invalid formatted URL' }, + { value: 13, text: '13 - Validation of protocol compliance: invalid POST format' }, + { value: 14, text: '14 - Validation of protocol compliance: invalid POST boundary' }, + { value: 15, text: '15 - Validation of protocol compliance: invalid JSON' }, + { value: 16, text: '16 - Validation of protocol compliance: POST with no body' }, + { value: 17, text: '17 - Possible SQL Injection attack: validation with libinjection_sql' }, + { value: 18, text: '18 - Possible XSS attack: validation with libinjection_xss' }, + { + value: 1000, + text: '1000 - Possible SQL Injection attack: SQL keywords found in Body, Path, Query String or Cookies' + }, + { + value: 1001, + text: '1001 - Possible SQL Injection or XSS attack: double quote (") found in Body, Path, Query String or Cookies' + }, + { + value: 1002, + text: '1002 - Possible SQL Injection attack: possible hex encoding (0x) found in Body, Path, Query String or Cookies' + }, + { + value: 1003, + text: '1003 - Possible SQL Injection attack: MySQL comment (/*) found in Body, Path, Query String or Cookies' + }, + { + value: 1004, + text: '1004 - Possible SQL Injection attack: MySQL comment (*/) found in Body, Path, Query String or Cookies' + }, + { + value: 1005, + text: '1005 - Possible SQL Injection attack: MySQL keyword (|) found in Body, Path, Query String or Cookies' + }, + { + value: 1006, + text: '1006 - Possible SQL Injection attack: MySQL keyword (&&) found in Body, Path, Query String or Cookies' + }, + { + value: 1007, + text: '1007 - Possible SQL Injection attack: MySQL comment (--) found in Body, Path, Query String or Cookies' + }, + { + value: 1008, + text: '1008 - Possible SQL Injection or XSS attack: semicolon (;) found in Body, Path or Query String' + }, + { + value: 1009, + text: '1009 - Possible SQL Injection attack: equal sign (=) found in Body or Query String' + }, + { + value: 1010, + text: '1010 - Possible SQL Injection or XSS attack: open parenthesis [(] found in Body, Path, Query String or Cookies' + }, + { + value: 1011, + text: '1011 - Possible SQL Injection or XSS attack: close parenthesis [)] found in Body, Path, Query String or Cookies' + }, + { + value: 1013, + text: "1013 - Possible SQL Injection or XSS attack: apostrophe (') found in Body, Path, Query String or Cookies" + }, + { + value: 1015, + text: '1015 - Possible SQL Injection attack: comma (,) found in Body, Path, Query String or Cookies' + }, + { + value: 1016, + text: '1016 - Possible SQL Injection attack: MySQL comment (#) found in Body, Path, Query String or Cookies' + }, + { + value: 1017, + text: '1017 - Possible SQL Injection attack: double at sign (@@) found in Body, Path, Query String or Cookies' + }, + { + value: 1100, + text: '1100 - Possible RFI attack: scheme "http://" found in Body, Query String or Cookies' + }, + { + value: 1101, + text: '1101 - Possible RFI attack: scheme "https://" found in Body, Query String or Cookies' + }, + { + value: 1102, + text: '1102 - Possible RFI attack: scheme "ftp://" found in Body, Query String or Cookies' + }, + { + value: 1103, + text: '1103 - Possible RFI attack: scheme "php://" found in Body, Query String or Cookies' + }, + { + value: 1104, + text: '1104 - Possible RFI attack: scheme "sftp://" found in Body, Query String or Cookies' + }, + { + value: 1105, + text: '1105 - Possible RFI attack: scheme "zlib://" found in Body, Query String or Cookies' + }, + { + value: 1106, + text: '1106 - Possible RFI attack: scheme "data://" found in Body, Query String or Cookies' + }, + { + value: 1107, + text: '1107 - Possible RFI attack: scheme "glob://" found in Body, Query String or Cookies' + }, + { + value: 1108, + text: '1108 - Possible RFI attack: scheme "phar://" found in Body, Query String or Cookies' + }, + { + value: 1109, + text: '1109 - Possible RFI attack: scheme "file://" found in Body, Query String or Cookies' + }, + { + value: 1110, + text: '1110 - Possible RFI attack: scheme "gopher://" found in Body, Query String or Cookies' + }, + { + value: 1198, + text: '1198 - Possible RCE attack: validation with log4j (Log4Shell) in HEADERS_VAR' + }, + { + value: 1199, + text: '1199 - Possible RCE attack: validation with log4j (Log4Shell) in Body, Path, Query String, Headers or Cookies' + }, + { + value: 1200, + text: '1200 - Possible Directory Traversal attack: double dot (..) found in Body, Path, Query String or Cookies' + }, + { + value: 1202, + text: '1202 - Possible Directory Traversal attack: obvious probe (/etc/passwd) found in Body, Path, Query String or Cookies' + }, + { + value: 1203, + text: `1203 - Possible Directory Traversal attack: obvious windows path (c:\\) found in Body, Path, Query String or Cookies` + }, + { + value: 1204, + text: '1204 - Possible Directory Traversal attack: obvious probe (cmd.exe) found in Body, Path, Query String or Cookies' + }, + { + value: 1205, + text: `1205 - Possible Directory Traversal attack: backslash (\) found in Body, Path, Query String or Cookies` + }, + { + value: 1206, + text: '1206 - Possible Directory Traversal attack: slash (/) found in Body, Query String or Cookies' + }, + { + value: 1207, + text: '1207 - Possible Directory Traversal attack: obvious path probe (/..;/) found in Body, Query String or Cookies' + }, + { + value: 1208, + text: '1208 - Possible Directory Traversal attack: obvious path probe (/.;/) found in Body, Query String or Cookies' + }, + { + value: 1209, + text: '1209 - Possible Directory Traversal attack: obvious path probe (/.%2e/) found in Body, Query String or Cookies' + }, + { + value: 1210, + text: '1210 - Possible Directory Traversal attack: obvious path probe (/%2e./) found in Body, Query String or Cookies' + }, + { + value: 1302, + text: '1302 - Possible XSS attack: html open tag (<) found in Body, Path, Query String or Cookies' + }, + { + value: 1303, + text: '1303 - Possible XSS attack: html close tag (>) found in Body, Path, Query String or Cookies' + }, + { + value: 1310, + text: '1310 - Possible XSS attack: open square bracket ([) found in Body, Path, Query String or Cookies' + }, + { + value: 1311, + text: '1311 - Possible XSS attack: close square bracket (]) found in Body, Path, Query String or Cookies' + }, + { + value: 1312, + text: '1312 - Possible XSS attack: tilde character (~) found in Body, Path, Query String or Cookies' + }, + { + value: 1314, + text: '1314 - Possible XSS attack: back quote ( `) found in Body, Path, Query String or Cookies' + }, + { + value: 1315, + text: '1315 - Possible XSS attack: double encoding (%[2|3]) found in Body, Path, Query String or Cookies' + }, + { + value: 1400, + text: '1400 - Possible trick to evade protection: UTF7/8 encoding (&#) found in Body, Path, Query String or Cookies' + }, + { + value: 1401, + text: '1401 - Possible trick to evade protection: MS encoding (%U) found in Body, Path, Query String or Cookies' + }, + { + value: 1402, + text: '1402 - Possible trick to evade protection: encoded chars (%20-%3F) found in Body, Query String or Cookies' + }, + { + value: 1500, + text: '1500 - Possible File Upload attempt: asp/php (.ph, .asp or .ht) found in filename in a multipart POST containing a file' + }, + { + value: 2001, + text: '2001 - Possible CVE-2022-22965 attack: Tomcat Pipeline Convalue: 0 ,text tampering' + } +] + +/* eslint-enable no-useless-escape */ diff --git a/src/templates/action-bar-block/action-bar-with-teleport.vue b/src/templates/action-bar-block/action-bar-with-teleport.vue index 1f94b169f..b41958cab 100644 --- a/src/templates/action-bar-block/action-bar-with-teleport.vue +++ b/src/templates/action-bar-block/action-bar-with-teleport.vue @@ -9,7 +9,8 @@ id: { type: String, default: '#action-bar' }, loading: Boolean, cancelDisabled: Boolean, - submitDisabled: Boolean + submitDisabled: Boolean, + primaryActionLabel: String }) const handleSubmit = () => { @@ -37,6 +38,7 @@ :cancelDisabled="props.cancelDisabled" :submitDisabled="props.submitDisabled" :inDrawer="false" + :primaryActionLabel="props.primaryActionLabel" @onSubmit="handleSubmit" @onCancel="handleCancel" /> diff --git a/src/templates/list-table-block/index.vue b/src/templates/list-table-block/index.vue index fd1d16ad5..05887d1fd 100644 --- a/src/templates/list-table-block/index.vue +++ b/src/templates/list-table-block/index.vue @@ -75,9 +75,10 @@ v-tooltip.top="{ value: 'Hidden Columns', showDelay: 200 }" > - +
@@ -44,6 +46,12 @@ rowReorder headerStyle="width: 3rem" /> + + 'No registers found.' + }, + dataFilted: { + type: Array, + default: () => [] + }, + hasListService: { + type: Boolean, + default: false + }, + showselectionMode: { + type: Boolean, + default: false + }, + cleanSelectData: { + type: Boolean, + default: false } }) @@ -237,6 +261,7 @@ const informationForDeletion = ref({}) const selectedItemData = ref(null) const selectedColumns = ref([]) + const selectedItems = ref() onMounted(() => { loadData({ page: 1 }) @@ -273,6 +298,7 @@ const loadData = async ({ page }) => { try { + if (props.hasListService) return isLoading.value = true const response = await props.listService({ page }) data.value = response @@ -364,4 +390,24 @@ const hasData = currentState.length > 0 emit('on-load-data', hasData) }) + + // to make a filter + + watch(selectedItems, (selectedData) => { + emit('on-select-data', selectedData) + }) + + watch( + () => props.dataFilted, + (newValue) => (data.value = newValue) + ) + + watch( + () => props.cleanSelectData, + (value) => { + if (value) { + selectedItems.value = [] + } + } + ) diff --git a/src/tests/services/credentials-services/create-credential-service.test.js b/src/tests/services/credentials-services/create-credential-service.test.js index 0ea52dcd5..74233930b 100644 --- a/src/tests/services/credentials-services/create-credential-service.test.js +++ b/src/tests/services/credentials-services/create-credential-service.test.js @@ -7,7 +7,8 @@ const fixtures = { basic: { name: 'Cred A', description: 'Some description', - token: 'test-token' + token: 'test-token', + status: true } } diff --git a/src/tests/services/domains-services/list-domains-service.test.js b/src/tests/services/domains-services/list-domains-service.test.js index 013a6789f..a4adf4e7c 100644 --- a/src/tests/services/domains-services/list-domains-service.test.js +++ b/src/tests/services/domains-services/list-domains-service.test.js @@ -9,7 +9,9 @@ const fixtures = { domain_name: 'domain A', cnames: ['CName 1', 'CName 2'], is_active: true, - digital_certificate_id: '862026' + activeSort: true, + digital_certificate_id: '862026', + edge_application_id: 'ea1234' }, disabledDomainMock: { id: '4132123', @@ -17,8 +19,14 @@ const fixtures = { domain_name: 'domain B', cnames: ['CName 3', 'CName 4'], is_active: false, - digital_certificate_id: '69870' - } + activeSort: false, + digital_certificate_id: '69870', + edge_application_id: 'ea5678' + }, + edgeApplicationsMock: [ + { id: 'ea1234', name: 'Edge App X', last_modified: new Date() }, + { id: 'ea5678', name: 'Edge App Y', last_modified: new Date() } + ] } const makeSut = () => { @@ -31,10 +39,17 @@ const makeSut = () => { describe('DomainsServices', () => { it('should call api with correct params', async () => { - const requestSpy = vi.spyOn(AxiosHttpClientAdapter, 'request').mockResolvedValueOnce({ - statusCode: 200, - body: { results: [] } - }) + const requestSpy = vi + .spyOn(AxiosHttpClientAdapter, 'request') + .mockResolvedValueOnce({ + statusCode: 200, + body: { results: [] } + }) + .mockResolvedValueOnce({ + statusCode: 200, + body: { results: fixtures.edgeApplicationsMock } + }) + const { sut } = makeSut() const version = 'v3' await sut({}) @@ -46,10 +61,16 @@ describe('DomainsServices', () => { }) it('should parsed correctly all returned domains', async () => { - vi.spyOn(AxiosHttpClientAdapter, 'request').mockResolvedValueOnce({ - statusCode: 200, - body: { results: [fixtures.domainMock, fixtures.disabledDomainMock] } - }) + vi.spyOn(AxiosHttpClientAdapter, 'request') + .mockResolvedValueOnce({ + statusCode: 200, + body: { results: [fixtures.domainMock, fixtures.disabledDomainMock] } + }) + .mockResolvedValueOnce({ + statusCode: 200, + body: { results: fixtures.edgeApplicationsMock } + }) + const { sut } = makeSut() const result = await sut({}) @@ -66,7 +87,8 @@ describe('DomainsServices', () => { content: 'Active', severity: 'success' }, - edgeApplicationName: fixtures.domainMock.name, + activeSort: true, + edgeApplicationName: fixtures.edgeApplicationsMock[0].name, digitalCertificateId: fixtures.domainMock.digital_certificate_id }, { @@ -80,7 +102,8 @@ describe('DomainsServices', () => { content: 'Inactive', severity: 'danger' }, - edgeApplicationName: fixtures.disabledDomainMock.name, + activeSort: false, + edgeApplicationName: fixtures.edgeApplicationsMock[1].name, digitalCertificateId: fixtures.disabledDomainMock.digital_certificate_id } ]) diff --git a/src/tests/services/edge-application-functions-services/list-edge-functions-service.test.js b/src/tests/services/edge-application-functions-services/list-edge-functions-service.test.js index 410dc13ca..bafd5d180 100644 --- a/src/tests/services/edge-application-functions-services/list-edge-functions-service.test.js +++ b/src/tests/services/edge-application-functions-services/list-edge-functions-service.test.js @@ -61,14 +61,14 @@ describe('EdgeFirewallFunctionsServices', () => { { label: 'function instance name', value: fixtures.functionsInstance.id, - args: fixtures.functionsInstance.json_args, - initiatorType: fixtures.functionsInstance.initiator_type, + args: '{}', + initiatorType: fixtures.functionsInstance.initiator_type }, { label: 'function instance version', value: fixtures.functionInstanceWithVersion.id, - args: fixtures.functionInstanceWithVersion.json_args, - initiatorType: fixtures.functionInstanceWithVersion.initiator_type, + args: '{}', + initiatorType: fixtures.functionInstanceWithVersion.initiator_type } ]) }) diff --git a/src/tests/services/edge-firewall-functions-services/list-functions-service.test.js b/src/tests/services/edge-firewall-functions-services/list-functions-service.test.js index 9991bc33e..109c66fac 100644 --- a/src/tests/services/edge-firewall-functions-services/list-functions-service.test.js +++ b/src/tests/services/edge-firewall-functions-services/list-functions-service.test.js @@ -61,14 +61,14 @@ describe('EdgeFirewallFunctionsServices', () => { { label: 'function instance name', value: fixtures.functionsInstance.id, - args: fixtures.functionsInstance.json_args, - initiatorType: fixtures.functionsInstance.initiator_type, + args: '{}', + initiatorType: fixtures.functionsInstance.initiator_type }, { label: 'function instance version', value: fixtures.functionInstanceWithVersion.id, - args: fixtures.functionInstanceWithVersion.json_args, - initiatorType: fixtures.functionInstanceWithVersion.initiator_type, + args: '{}', + initiatorType: fixtures.functionInstanceWithVersion.initiator_type } ]) }) diff --git a/src/tests/services/waf-rules-services/create-waf-rules-allowed-service.test.js b/src/tests/services/waf-rules-services/create-waf-rules-allowed-service.test.js index b9a025f60..732e05a10 100644 --- a/src/tests/services/waf-rules-services/create-waf-rules-allowed-service.test.js +++ b/src/tests/services/waf-rules-services/create-waf-rules-allowed-service.test.js @@ -57,7 +57,9 @@ describe('WafRulesServices', () => { const data = await sut({ payload: fixtures.wafRulesMock, id: 10 }) - expect(data).toStrictEqual('Your waf rule allowed has been created') + expect(data).toStrictEqual({ + feedback: 'Your waf rule allowed has been created' + }) }) it('Should return an API error for an 400 response status', async () => { diff --git a/src/tests/services/waf-rules-services/create-waf-rules-allowed-tuning-service.test.js b/src/tests/services/waf-rules-services/create-waf-rules-allowed-tuning-service.test.js new file mode 100644 index 000000000..55d5daab9 --- /dev/null +++ b/src/tests/services/waf-rules-services/create-waf-rules-allowed-tuning-service.test.js @@ -0,0 +1,110 @@ +import { AxiosHttpClientAdapter } from '@/services/axios/AxiosHttpClientAdapter' +import * as Errors from '@/services/axios/errors' +import { createWafRulesAllowedTuningService } from '@/services/waf-rules-services' +import { describe, expect, it, vi } from 'vitest' + +const fixtures = { + wafRulesMock: { + reason: 'Allowed Rules created to allow the attack', + matchZone: [ + { + zone: 'conditional_query_string', + zone_input: 'arg', + matches_on: 'value' + } + ], + ruleId: '1000' + } +} + +const makeSut = () => { + const sut = createWafRulesAllowedTuningService + + return { + sut + } +} + +describe('WafRulesServices', () => { + it('should call API with correct params', async () => { + const requestSpy = vi.spyOn(AxiosHttpClientAdapter, 'request').mockResolvedValueOnce({ + statusCode: 202, + body: fixtures.wafRulesMock + }) + const { sut } = makeSut() + await sut({ payload: fixtures.wafRulesMock, wafId: 10 }) + + expect(requestSpy).toHaveBeenCalledWith({ + url: 'v4/edge/waf/10/allowed_rules', + method: 'POST', + body: { + rule_id: fixtures.wafRulesMock.ruleId, + match_zones: fixtures.wafRulesMock.matchZone, + reason: fixtures.wafRulesMock.reason + } + }) + }) + + it('should return a feedback message on successfully created', async () => { + vi.spyOn(AxiosHttpClientAdapter, 'request').mockResolvedValueOnce({ + statusCode: 202, + body: fixtures.wafRulesMock + }) + const { sut } = makeSut() + + const data = await sut({ payload: fixtures.wafRulesMock, wafId: 10 }) + + expect(data).toStrictEqual('Your waf rule allowed has been created') + }) + + it('Should return an API error for an 400 response status', async () => { + const errorKey = 'detail' + const apiErrorMock = 'This field is required.' + vi.spyOn(AxiosHttpClientAdapter, 'request').mockResolvedValueOnce({ + statusCode: 400, + body: { + [errorKey]: [{ error: [apiErrorMock] }] + } + }) + const { sut } = makeSut() + + const feedbackMessage = sut({ payload: fixtures.wafRulesMock, wafId: 10 }) + + expect(feedbackMessage).rejects.toThrow(apiErrorMock) + }) + + it.each([ + { + statusCode: 401, + expectedError: new Errors.InvalidApiTokenError().message + }, + { + statusCode: 403, + expectedError: new Errors.PermissionError().message + }, + { + statusCode: 404, + expectedError: new Errors.NotFoundError().message + }, + { + statusCode: 500, + expectedError: new Errors.InternalServerError().message + }, + { + statusCode: 'unmappedStatusCode', + expectedError: new Errors.UnexpectedError().message + } + ])( + 'should throw when request fails with status code $statusCode', + async ({ statusCode, expectedError }) => { + vi.spyOn(AxiosHttpClientAdapter, 'request').mockResolvedValueOnce({ + statusCode + }) + const { sut } = makeSut() + + const response = sut({ payload: fixtures.wafRulesMock, id: 10 }) + + expect(response).rejects.toBe(expectedError) + } + ) +}) diff --git a/src/tests/services/waf-rules-services/delete-waf-rules-allowed-service.test.js b/src/tests/services/waf-rules-services/delete-waf-rules-allowed-service.test.js index 14c1c21ea..6456eee76 100644 --- a/src/tests/services/waf-rules-services/delete-waf-rules-allowed-service.test.js +++ b/src/tests/services/waf-rules-services/delete-waf-rules-allowed-service.test.js @@ -14,7 +14,7 @@ const makeSut = () => { describe('WafRulesServices', () => { it('should call API with correct params', async () => { const requestSpy = vi.spyOn(AxiosHttpClientAdapter, 'request').mockResolvedValueOnce({ - statusCode: 200 + statusCode: 202 }) const wafRuleIdMock = 765678 const { sut } = makeSut() @@ -28,7 +28,7 @@ describe('WafRulesServices', () => { it('should return a feedback message on successfully deleted', async () => { vi.spyOn(AxiosHttpClientAdapter, 'request').mockResolvedValueOnce({ - statusCode: 200 + statusCode: 202 }) const wafRuleIdMock = 7816825367 const { sut } = makeSut() diff --git a/src/tests/services/waf-rules-services/edit-waf-rules-allowed-service.test.js b/src/tests/services/waf-rules-services/edit-waf-rules-allowed-service.test.js index 2db03d424..4753a8eb3 100644 --- a/src/tests/services/waf-rules-services/edit-waf-rules-allowed-service.test.js +++ b/src/tests/services/waf-rules-services/edit-waf-rules-allowed-service.test.js @@ -25,7 +25,7 @@ const makeSut = () => { describe('WafRulesServices', () => { it('should call API with correct params', async () => { const requestSpy = vi.spyOn(AxiosHttpClientAdapter, 'request').mockResolvedValueOnce({ - statusCode: 200, + statusCode: 202, body: fixtures.wafRulesMock }) const { sut } = makeSut() @@ -47,7 +47,7 @@ describe('WafRulesServices', () => { it('should return a feedback message on successfully updated', async () => { vi.spyOn(AxiosHttpClientAdapter, 'request').mockResolvedValueOnce({ - statusCode: 200, + statusCode: 202, body: fixtures.wafRulesMock }) const { sut } = makeSut() diff --git a/src/tests/services/waf-rules-services/list-network-list-service.test.js b/src/tests/services/waf-rules-services/list-network-list-service.test.js new file mode 100644 index 000000000..0719b019b --- /dev/null +++ b/src/tests/services/waf-rules-services/list-network-list-service.test.js @@ -0,0 +1,63 @@ +import { AxiosHttpClientAdapter } from '@/services/axios/AxiosHttpClientAdapter' +import { listNetworkListService } from '@/services/waf-rules-services' +import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest' + +const fixtures = { + networkMock: { + id: 123123123, + name: 'Network AZ' + } +} + +const makeSut = () => { + const sut = listNetworkListService + + return { + sut + } +} + +describe('WafRulesServices', () => { + beforeEach(() => { + vi.useFakeTimers() + }) + afterEach(() => { + vi.useRealTimers() + }) + + it('should call api with correct params', async () => { + const requestSpy = vi.spyOn(AxiosHttpClientAdapter, 'request').mockResolvedValueOnce({ + statusCode: 200, + body: { + results: null + } + }) + + const { sut } = makeSut() + await sut() + + expect(requestSpy).toHaveBeenCalledWith({ + url: `v3/network_lists?pagination=false&exclude_azion_lists=true`, + method: 'GET' + }) + }) + + it('should parsed correctly each network record', async () => { + vi.spyOn(AxiosHttpClientAdapter, 'request').mockResolvedValueOnce({ + statusCode: 200, + body: { + results: [fixtures.networkMock] + } + }) + const { sut } = makeSut() + + const result = await sut() + + expect(result).toEqual([ + { + id: fixtures.networkMock.id, + name: fixtures.networkMock.name + } + ]) + }) +}) diff --git a/src/tests/services/waf-rules-services/list-waf-rules-allowed-service.test.js b/src/tests/services/waf-rules-services/list-waf-rules-allowed-service.test.js index 8d4cf5e55..022c91767 100644 --- a/src/tests/services/waf-rules-services/list-waf-rules-allowed-service.test.js +++ b/src/tests/services/waf-rules-services/list-waf-rules-allowed-service.test.js @@ -54,7 +54,7 @@ describe('WafRulesServices', () => { await sut({ wafId: 4040 }) expect(requestSpy).toHaveBeenCalledWith({ - url: 'v4/edge/waf/4040/allowed_rules?page=1&page_size=100', + url: 'v4/edge/waf/4040/allowed_rules?page=1&page_size=200', method: 'GET' }) }) diff --git a/src/tests/services/waf-rules-services/list-waf-rules-domain-service.test.js b/src/tests/services/waf-rules-services/list-waf-rules-domain-service.test.js new file mode 100644 index 000000000..e6873f689 --- /dev/null +++ b/src/tests/services/waf-rules-services/list-waf-rules-domain-service.test.js @@ -0,0 +1,62 @@ +import { AxiosHttpClientAdapter } from '@/services/axios/AxiosHttpClientAdapter' +import { listWafRulesDomainsService } from '@/services/waf-rules-services' +import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest' + +const fixtures = { + wafRulesDomainMock: { + cnames: [], + domain: 'erwc1eveo1.map.azionedge.net', + id: 1705587704, + name: 'atack' + } +} + +const makeSut = () => { + const sut = listWafRulesDomainsService + + return { + sut + } +} + +describe('WafRulesServices', () => { + beforeEach(() => { + vi.useFakeTimers() + }) + afterEach(() => { + vi.useRealTimers() + }) + + it('should call api with correct params', async () => { + const requestSpy = vi.spyOn(AxiosHttpClientAdapter, 'request').mockResolvedValueOnce({ + statusCode: 200, + body: { result: null } + }) + + const { sut } = makeSut() + await sut({ wafId: 100 }) + + expect(requestSpy).toHaveBeenCalledWith({ + url: 'v3/waf/100/domains', + method: 'GET' + }) + }) + + it('should parsed correctly domain', async () => { + vi.spyOn(AxiosHttpClientAdapter, 'request').mockResolvedValueOnce({ + statusCode: 200, + body: { results: [fixtures.wafRulesDomainMock] } + }) + const { sut } = makeSut() + + const result = await sut({ wafId: 100 }) + + expect(result).toEqual([ + { + domain: fixtures.wafRulesDomainMock.domain, + id: fixtures.wafRulesDomainMock.id, + name: fixtures.wafRulesDomainMock.name + } + ]) + }) +}) diff --git a/src/tests/services/waf-rules-services/list-waf-rules-service.test.js b/src/tests/services/waf-rules-services/list-waf-rules-service.test.js index 872a7e376..b89940f01 100644 --- a/src/tests/services/waf-rules-services/list-waf-rules-service.test.js +++ b/src/tests/services/waf-rules-services/list-waf-rules-service.test.js @@ -78,7 +78,7 @@ describe('WafRulesServices', () => { await sut() expect(requestSpy).toHaveBeenCalledWith({ - url: 'v3/waf/?page=1&page_size=100', + url: 'v3/waf/?page=1&page_size=200', method: 'GET' }) }) diff --git a/src/tests/services/waf-rules-services/list-waf-rules-tuning-attack-service.test.js b/src/tests/services/waf-rules-services/list-waf-rules-tuning-attack-service.test.js new file mode 100644 index 000000000..bcdf6a4f1 --- /dev/null +++ b/src/tests/services/waf-rules-services/list-waf-rules-tuning-attack-service.test.js @@ -0,0 +1,81 @@ +import { AxiosHttpClientAdapter } from '@/services/axios/AxiosHttpClientAdapter' +import { listWafRulesTuningAttacksService } from '@/services/waf-rules-services' +import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest' + +const fixtures = { + wafRulesMock: { + hit_count: 10, + top_10_ips: [{ ip: '120.103.10' }], + rule_id: 1000, + ip_count: 8, + match_zone: 'value', + path_count: 10, + top_10_countries: [{ country: 'Brazil' }], + matches_on: 'query_string', + country_count: 10, + match_value: 'value', + top_10_paths: [{ path: '/get' }] + } +} + +const makeSut = () => { + const sut = listWafRulesTuningAttacksService + + return { + sut + } +} + +describe('WafRulesService', () => { + beforeEach(() => { + vi.useFakeTimers() + }) + afterEach(() => { + vi.useRealTimers() + }) + it('should call api with correct params', async () => { + const requestSpy = vi.spyOn(AxiosHttpClientAdapter, 'request').mockResolvedValueOnce({ + statusCode: 200, + body: { results: [fixtures.wafRulesMock] } + }) + const { sut } = makeSut() + await sut({ wafId: 4044, query: '?hour_range=48&domains_ids=1705587704', tuningId: 100 }) + + expect(requestSpy).toHaveBeenCalledWith({ + url: 'v3/waf/4044/waf_events/100?hour_range=48&domains_ids=1705587704', + method: 'GET' + }) + }) + + it('should parsed correctly the returned waf rules tuning', async () => { + vi.spyOn(AxiosHttpClientAdapter, 'request').mockResolvedValueOnce({ + statusCode: 200, + body: { results: [fixtures.wafRulesMock] } + }) + const { sut } = makeSut() + + const result = await sut({ + wafId: 4044, + query: '?hour_range=48&domains_ids=1705587704', + tuningId: 100 + }) + + expect(result).toEqual([ + { + hitCount: fixtures.wafRulesMock.hit_count, + topIps: ['120.103.10'], + id: 0, + ruleId: fixtures.wafRulesMock.rule_id, + ipCount: fixtures.wafRulesMock.ip_count, + matchZone: fixtures.wafRulesMock.match_zone, + pathCount: fixtures.wafRulesMock.path_count, + topCountries: ['Brazil'], + matchesOn: fixtures.wafRulesMock.matches_on, + ruleDescription: fixtures.wafRulesMock.rule_description, + countryCount: fixtures.wafRulesMock.country_count, + topPaths: ['/get'], + matchValue: fixtures.wafRulesMock.match_value + } + ]) + }) +}) diff --git a/src/tests/services/waf-rules-services/list-waf-rules-tuning-service.test.js b/src/tests/services/waf-rules-services/list-waf-rules-tuning-service.test.js new file mode 100644 index 000000000..5bffdcbee --- /dev/null +++ b/src/tests/services/waf-rules-services/list-waf-rules-tuning-service.test.js @@ -0,0 +1,74 @@ +import { AxiosHttpClientAdapter } from '@/services/axios/AxiosHttpClientAdapter' +import { listWafRulesTuningService } from '@/services/waf-rules-services' +import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest' + +const fixtures = { + wafRulesMock: { + hit_count: 10, + top_10_ips: [['', '100.100.10']], + rule_id: 1000, + ip_count: 8, + match_zone: 'value', + path_count: 10, + top_10_countries: [['', 'Brazil']], + matches_on: 'query_string', + rule_description: 'Possible SQL Injection attack: SQL keywords found in Query String', + country_count: 10 + } +} + +const makeSut = () => { + const sut = listWafRulesTuningService + + return { + sut + } +} + +describe('WafRulesService', () => { + beforeEach(() => { + vi.useFakeTimers() + }) + afterEach(() => { + vi.useRealTimers() + }) + it('should call api with correct params', async () => { + const requestSpy = vi.spyOn(AxiosHttpClientAdapter, 'request').mockResolvedValueOnce({ + statusCode: 200, + body: { results: [fixtures.wafRulesMock] } + }) + const { sut } = makeSut() + await sut({ wafId: 4044, query: '?hour_range=48&domains_ids=1705587704' }) + + expect(requestSpy).toHaveBeenCalledWith({ + url: 'v3/waf/4044/waf_events?hour_range=48&domains_ids=1705587704', + method: 'GET' + }) + }) + + it('should parsed correctly the returned waf rules tuning', async () => { + vi.spyOn(AxiosHttpClientAdapter, 'request').mockResolvedValueOnce({ + statusCode: 200, + body: { results: [fixtures.wafRulesMock] } + }) + const { sut } = makeSut() + + const result = await sut({ wafId: 4044, query: '?hour_range=48&domains_ids=1705587704' }) + + expect(result).toEqual([ + { + hitCount: fixtures.wafRulesMock.hit_count, + topIps: '100.100.10', + id: fixtures.wafRulesMock.rule_id, + ruleIdDescription: `${fixtures.wafRulesMock.rule_id} - ${fixtures.wafRulesMock.rule_description}`, + ipCount: fixtures.wafRulesMock.ip_count, + matchZone: fixtures.wafRulesMock.match_zone, + pathCount: fixtures.wafRulesMock.path_count, + topCountries: 'Brazil', + matchesOn: fixtures.wafRulesMock.matches_on, + ruleDescription: fixtures.wafRulesMock.rule_description, + countryCount: fixtures.wafRulesMock.country_count + } + ]) + }) +}) diff --git a/src/views/CliCallback/FailView.vue b/src/views/CliCallback/FailView.vue index cd2883dcf..f27a560d0 100644 --- a/src/views/CliCallback/FailView.vue +++ b/src/views/CliCallback/FailView.vue @@ -16,7 +16,8 @@

- For assistance, you can refer to the documentation, contact Azion Support, or check the Azion Community. + For assistance, you can refer to the documentation, contact Azion Support, or check the Azion + Community.

diff --git a/src/views/Domains/ListView.vue b/src/views/Domains/ListView.vue index e1204d79b..aaabe7c9a 100644 --- a/src/views/Domains/ListView.vue +++ b/src/views/Domains/ListView.vue @@ -92,6 +92,7 @@ }, { field: 'active', + sortField: 'activeSort', header: 'Status', type: 'component', component: (columnData) => diff --git a/src/views/EdgeApplicationsFunctions/FormFields/FormFieldsEdgeApplicationsFunctions.vue b/src/views/EdgeApplicationsFunctions/FormFields/FormFieldsEdgeApplicationsFunctions.vue index 15678f64f..b4748cea2 100644 --- a/src/views/EdgeApplicationsFunctions/FormFields/FormFieldsEdgeApplicationsFunctions.vue +++ b/src/views/EdgeApplicationsFunctions/FormFields/FormFieldsEdgeApplicationsFunctions.vue @@ -30,7 +30,6 @@ formatOnPaste: true } }) - const { value: name } = useField('name') const { value: edgeFunctionID } = useField('edgeFunctionID') const { value: args } = useField('args') @@ -44,7 +43,7 @@ @@ -59,8 +59,8 @@ diff --git a/src/views/EdgeFirewallFunctions/FormFields/FormFieldsEdgeApplicationsFunctions.vue b/src/views/EdgeFirewallFunctions/FormFields/FormFieldsEdgeApplicationsFunctions.vue index 537dcb9f0..c9ab3d684 100644 --- a/src/views/EdgeFirewallFunctions/FormFields/FormFieldsEdgeApplicationsFunctions.vue +++ b/src/views/EdgeFirewallFunctions/FormFields/FormFieldsEdgeApplicationsFunctions.vue @@ -14,7 +14,7 @@ }) const store = useAccountStore() - + const changeArgs = (target) => { props.edgeFunctionsList.forEach((element) => { if (element.value === target.value) { diff --git a/src/views/WafRules/CreateView.vue b/src/views/WafRules/CreateView.vue index 163222e11..9711a5422 100644 --- a/src/views/WafRules/CreateView.vue +++ b/src/views/WafRules/CreateView.vue @@ -61,6 +61,7 @@ }) const initialValues = { + name: '', crossSiteScriptingSensitivity: 'medium', directoryTraversalSensitivity: 'medium', evadingTricksSensitivity: 'medium', diff --git a/src/views/WafRules/Dialog/index.vue b/src/views/WafRules/Dialog/index.vue new file mode 100644 index 000000000..9323ae531 --- /dev/null +++ b/src/views/WafRules/Dialog/index.vue @@ -0,0 +1,107 @@ + + +