Skip to content

Commit

Permalink
custom validator for ENVs with URL value (#1238)
Browse files Browse the repository at this point in the history
Fixes #1236
  • Loading branch information
tom2drum authored Oct 2, 2023
1 parent 1690f53 commit 38d373c
Show file tree
Hide file tree
Showing 6 changed files with 63 additions and 35 deletions.
2 changes: 1 addition & 1 deletion configs/envs/.env.eth
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ NEXT_PUBLIC_APP_ENV=development
NEXT_PUBLIC_GRAPHIQL_TRANSACTION=0xf7d4972356e6ae44ae948d0cf19ef2beaf0e574c180997e969a2837da15e349d
NEXT_PUBLIC_HAS_BEACON_CHAIN=true
NEXT_PUBLIC_IS_ACCOUNT_SUPPORTED=true
# NEXT_PUBLIC_AUTH_URL=http://localhost:3000
NEXT_PUBLIC_AUTH_URL=http://localhost:3000
NEXT_PUBLIC_LOGOUT_URL=https://blockscoutcom.us.auth0.com/v2/logout
NEXT_PUBLIC_STATS_API_HOST=https://stats-eth-main.k8s.blockscout.com
NEXT_PUBLIC_VISUALIZE_API_HOST=https://visualizer.services.blockscout.com
Expand Down
2 changes: 1 addition & 1 deletion configs/envs/.env.eth_goerli
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ NEXT_PUBLIC_APP_INSTANCE=local
NEXT_PUBLIC_APP_ENV=development
NEXT_PUBLIC_GRAPHIQL_TRANSACTION=0xf7d4972356e6ae44ae948d0cf19ef2beaf0e574c180997e969a2837da15e349d
NEXT_PUBLIC_IS_ACCOUNT_SUPPORTED=true
# NEXT_PUBLIC_AUTH_URL=http://localhost:3000
NEXT_PUBLIC_AUTH_URL=http://localhost:3000
NEXT_PUBLIC_LOGOUT_URL=https://blockscoutcom.us.auth0.com/v2/logout
NEXT_PUBLIC_MARKETPLACE_CONFIG_URL=https://raw.githubusercontent.com/blockscout/frontend-configs/dev/configs/marketplace/eth-goerli.json
NEXT_PUBLIC_MARKETPLACE_SUBMIT_FORM=https://airtable.com/shrqUAcjgGJ4jU88C
Expand Down
2 changes: 1 addition & 1 deletion configs/envs/.env.localhost
Original file line number Diff line number Diff line change
Expand Up @@ -36,5 +36,5 @@ NEXT_PUBLIC_NETWORK_EXPLORERS=[{'title':'Anyblock','baseUrl':'https://explorer.a
NEXT_PUBLIC_APP_INSTANCE=local
NEXT_PUBLIC_APP_ENV=development
NEXT_PUBLIC_IS_ACCOUNT_SUPPORTED=true
# NEXT_PUBLIC_AUTH_URL=http://localhost:3000
NEXT_PUBLIC_AUTH_URL=http://localhost:3000
NEXT_PUBLIC_LOGOUT_URL=https://blockscoutcom.us.auth0.com/v2/logout
2 changes: 1 addition & 1 deletion configs/envs/.env.main
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ NEXT_PUBLIC_APP_INSTANCE=local
NEXT_PUBLIC_APP_ENV=development
NEXT_PUBLIC_GRAPHIQL_TRANSACTION=0xf7d4972356e6ae44ae948d0cf19ef2beaf0e574c180997e969a2837da15e349d
NEXT_PUBLIC_IS_ACCOUNT_SUPPORTED=true
# NEXT_PUBLIC_AUTH_URL=http://localhost:3000
NEXT_PUBLIC_AUTH_URL=http://localhost:3000
NEXT_PUBLIC_LOGOUT_URL=https://blockscoutcom.us.auth0.com/v2/logout
NEXT_PUBLIC_MARKETPLACE_CONFIG_URL=https://raw.githubusercontent.com/blockscout/frontend-configs/dev/configs/marketplace/eth-goerli.json
NEXT_PUBLIC_MARKETPLACE_SUBMIT_FORM=https://airtable.com/shrqUAcjgGJ4jU88C
Expand Down
2 changes: 1 addition & 1 deletion configs/envs/.env.poa_core
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ NEXT_PUBLIC_NETWORK_EXPLORERS=[{'title':'Anyblock','baseUrl':'https://explorer.a
NEXT_PUBLIC_APP_INSTANCE=local
NEXT_PUBLIC_APP_ENV=development
NEXT_PUBLIC_IS_ACCOUNT_SUPPORTED=true
# NEXT_PUBLIC_AUTH_URL=http://localhost:3000
NEXT_PUBLIC_AUTH_URL=http://localhost:3000
NEXT_PUBLIC_LOGOUT_URL=https://blockscoutcom.us.auth0.com/v2/logout
NEXT_PUBLIC_NETWORK_VERIFICATION_TYPE=validation
NEXT_PUBLIC_NETWORK_RPC_URL=https://core.poa.network
88 changes: 58 additions & 30 deletions deploy/tools/envs-validator/schema.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,11 @@
declare module 'yup' {
interface StringSchema {
// Yup's URL validator is not perfect so we made our own
// https://github.com/jquense/yup/pull/1859
url(): never;
}
}

import * as yup from 'yup';

import type { AdButlerConfig } from '../../../types/client/adButlerConfig';
Expand All @@ -19,22 +27,42 @@ import * as regexp from '../../../lib/regexp';

const protocols = [ 'http', 'https' ];

const urlTest: yup.TestConfig = {
name: 'url',
test: (value: unknown) => {
if (!value) {
return true;
}

try {
if (typeof value === 'string') {
new URL(value);
return true;
}
} catch (error) {}

return false;
},
message: '${path} is not a valid URL',
exclusive: true,
};

const marketplaceAppSchema: yup.ObjectSchema<MarketplaceAppOverview> = yup
.object({
id: yup.string().required(),
external: yup.boolean(),
title: yup.string().required(),
logo: yup.string().url().required(),
logoDarkMode: yup.string().url(),
logo: yup.string().test(urlTest).required(),
logoDarkMode: yup.string().test(urlTest),
shortDescription: yup.string().required(),
categories: yup.array().of(yup.string().required()).required(),
url: yup.string().url().required(),
url: yup.string().test(urlTest).required(),
author: yup.string().required(),
description: yup.string().required(),
site: yup.string().url(),
twitter: yup.string().url(),
telegram: yup.string().url(),
github: yup.string().url(),
site: yup.string().test(urlTest),
twitter: yup.string().test(urlTest),
telegram: yup.string().test(urlTest),
github: yup.string().test(urlTest),
});

const marketplaceSchema = yup
Expand All @@ -48,7 +76,7 @@ const marketplaceSchema = yup
.string()
.when('NEXT_PUBLIC_MARKETPLACE_CONFIG_URL', {
is: (value: Array<unknown>) => value.length > 0,
then: (schema) => schema.url().required(),
then: (schema) => schema.test(urlTest).required(),
otherwise: (schema) => schema.max(-1, 'NEXT_PUBLIC_MARKETPLACE_SUBMIT_FORM cannot not be used without NEXT_PUBLIC_MARKETPLACE_CONFIG_URL'),
}),
});
Expand Down Expand Up @@ -77,14 +105,14 @@ const rollupSchema = yup
.string()
.when('NEXT_PUBLIC_IS_L2_NETWORK', {
is: (value: boolean) => value,
then: (schema) => schema.url().required(),
then: (schema) => schema.test(urlTest).required(),
otherwise: (schema) => schema.max(-1, 'NEXT_PUBLIC_L1_BASE_URL cannot not be used if NEXT_PUBLIC_IS_L2_NETWORK is not set to "true"'),
}),
NEXT_PUBLIC_L2_WITHDRAWAL_URL: yup
.string()
.when('NEXT_PUBLIC_IS_L2_NETWORK', {
is: (value: string) => value,
then: (schema) => schema.url().required(),
then: (schema) => schema.test(urlTest).required(),
otherwise: (schema) => schema.max(-1, 'NEXT_PUBLIC_L2_WITHDRAWAL_URL cannot not be used if NEXT_PUBLIC_IS_L2_NETWORK is not set to "true"'),
}),
});
Expand Down Expand Up @@ -115,12 +143,12 @@ const adsBannerSchema = yup
const sentrySchema = yup
.object()
.shape({
NEXT_PUBLIC_SENTRY_DSN: yup.string().url(),
NEXT_PUBLIC_SENTRY_DSN: yup.string().test(urlTest),
SENTRY_CSP_REPORT_URI: yup
.string()
.when('NEXT_PUBLIC_SENTRY_DSN', {
is: (value: string) => Boolean(value),
then: (schema) => schema.url(),
then: (schema) => schema.test(urlTest),
otherwise: (schema) => schema.max(-1, 'SENTRY_CSP_REPORT_URI cannot not be used without NEXT_PUBLIC_SENTRY_DSN'),
}),
NEXT_PUBLIC_APP_INSTANCE: yup
Expand Down Expand Up @@ -154,21 +182,21 @@ const accountSchema = yup
.string()
.when('NEXT_PUBLIC_IS_ACCOUNT_SUPPORTED', {
is: (value: boolean) => value,
then: (schema) => schema.url(),
then: (schema) => schema.test(urlTest),
otherwise: (schema) => schema.max(-1, 'NEXT_PUBLIC_AUTH_URL cannot not be used if NEXT_PUBLIC_IS_ACCOUNT_SUPPORTED is not set to "true"'),
}),
NEXT_PUBLIC_LOGOUT_URL: yup
.string()
.when('NEXT_PUBLIC_IS_ACCOUNT_SUPPORTED', {
is: (value: boolean) => value,
then: (schema) => schema.url().required(),
then: (schema) => schema.test(urlTest).required(),
otherwise: (schema) => schema.max(-1, 'NEXT_PUBLIC_LOGOUT_URL cannot not be used if NEXT_PUBLIC_IS_ACCOUNT_SUPPORTED is not set to "true"'),
}),
NEXT_PUBLIC_ADMIN_SERVICE_API_HOST: yup
.string()
.when('NEXT_PUBLIC_IS_ACCOUNT_SUPPORTED', {
is: (value: boolean) => value,
then: (schema) => schema.url(),
then: (schema) => schema.test(urlTest),
otherwise: (schema) => schema.max(-1, 'NEXT_PUBLIC_ADMIN_SERVICE_API_HOST cannot not be used if NEXT_PUBLIC_IS_ACCOUNT_SUPPORTED is not set to "true"'),
}),
});
Expand All @@ -177,23 +205,23 @@ const featuredNetworkSchema: yup.ObjectSchema<FeaturedNetwork> = yup
.object()
.shape({
title: yup.string().required(),
url: yup.string().url().required(),
url: yup.string().test(urlTest).required(),
group: yup.string().oneOf(NETWORK_GROUPS).required(),
icon: yup.string().url(),
icon: yup.string().test(urlTest),
isActive: yup.boolean(),
invertIconInDarkMode: yup.boolean(),
});

const navItemExternalSchema: yup.ObjectSchema<NavItemExternal> = yup
.object({
text: yup.string().required(),
url: yup.string().url().required(),
url: yup.string().test(urlTest).required(),
});

const footerLinkSchema: yup.ObjectSchema<CustomLink> = yup
.object({
text: yup.string().required(),
url: yup.string().url().required(),
url: yup.string().test(urlTest).required(),
});

const footerLinkGroupSchema: yup.ObjectSchema<CustomLinksGroup> = yup
Expand All @@ -208,7 +236,7 @@ const footerLinkGroupSchema: yup.ObjectSchema<CustomLinksGroup> = yup
const networkExplorerSchema: yup.ObjectSchema<NetworkExplorer> = yup
.object({
title: yup.string().required(),
baseUrl: yup.string().url().required(),
baseUrl: yup.string().test(urlTest).required(),
paths: yup
.object()
.shape({
Expand Down Expand Up @@ -241,7 +269,7 @@ const schema = yup
NEXT_PUBLIC_NETWORK_NAME: yup.string().required(),
NEXT_PUBLIC_NETWORK_SHORT_NAME: yup.string(),
NEXT_PUBLIC_NETWORK_ID: yup.number().positive().integer().required(),
NEXT_PUBLIC_NETWORK_RPC_URL: yup.string().url(),
NEXT_PUBLIC_NETWORK_RPC_URL: yup.string().test(urlTest),
NEXT_PUBLIC_NETWORK_CURRENCY_NAME: yup.string(),
NEXT_PUBLIC_NETWORK_CURRENCY_SYMBOL: yup.string(),
NEXT_PUBLIC_NETWORK_CURRENCY_DECIMALS: yup.number().integer().positive(),
Expand Down Expand Up @@ -278,10 +306,10 @@ const schema = yup
.transform(getEnvValue)
.json()
.of(navItemExternalSchema),
NEXT_PUBLIC_NETWORK_LOGO: yup.string().url(),
NEXT_PUBLIC_NETWORK_LOGO_DARK: yup.string().url(),
NEXT_PUBLIC_NETWORK_ICON: yup.string().url(),
NEXT_PUBLIC_NETWORK_ICON_DARK: yup.string().url(),
NEXT_PUBLIC_NETWORK_LOGO: yup.string().test(urlTest),
NEXT_PUBLIC_NETWORK_LOGO_DARK: yup.string().test(urlTest),
NEXT_PUBLIC_NETWORK_ICON: yup.string().test(urlTest),
NEXT_PUBLIC_NETWORK_ICON_DARK: yup.string().test(urlTest),

// c. footer
NEXT_PUBLIC_FOOTER_LINKS: yup
Expand All @@ -307,10 +335,10 @@ const schema = yup
NEXT_PUBLIC_MAINTENANCE_ALERT_MESSAGE: yup.string(),

// 5. Features configuration
NEXT_PUBLIC_API_SPEC_URL: yup.string().url(),
NEXT_PUBLIC_STATS_API_HOST: yup.string().url(),
NEXT_PUBLIC_VISUALIZE_API_HOST: yup.string().url(),
NEXT_PUBLIC_CONTRACT_INFO_API_HOST: yup.string().url(),
NEXT_PUBLIC_API_SPEC_URL: yup.string().test(urlTest),
NEXT_PUBLIC_STATS_API_HOST: yup.string().test(urlTest),
NEXT_PUBLIC_VISUALIZE_API_HOST: yup.string().test(urlTest),
NEXT_PUBLIC_CONTRACT_INFO_API_HOST: yup.string().test(urlTest),
NEXT_PUBLIC_GRAPHIQL_TRANSACTION: yup.string().matches(regexp.HEX_REGEXP),
NEXT_PUBLIC_WEB3_WALLETS: yup
.mixed()
Expand All @@ -328,7 +356,7 @@ const schema = yup
NEXT_PUBLIC_AD_TEXT_PROVIDER: yup.string<AdTextProviders>().oneOf(SUPPORTED_AD_TEXT_PROVIDERS),
NEXT_PUBLIC_PROMOTE_BLOCKSCOUT_IN_TITLE: yup.boolean(),
NEXT_PUBLIC_OG_DESCRIPTION: yup.string(),
NEXT_PUBLIC_OG_IMAGE_URL: yup.string().url(),
NEXT_PUBLIC_OG_IMAGE_URL: yup.string().test(urlTest),

// 6. External services envs
NEXT_PUBLIC_WALLET_CONNECT_PROJECT_ID: yup.string(),
Expand Down

0 comments on commit 38d373c

Please sign in to comment.