release: prepare August 1 Android RC
This commit is contained in:
@@ -0,0 +1,81 @@
|
||||
export type LegalDocumentKind = 'terms' | 'privacy';
|
||||
|
||||
const placeholderPattern = /__|change[-_ ]?me|your[-_ ]?|example\.(com|org|net)/i;
|
||||
const reservedHostnamePattern = /(?:^|\.)(?:example|invalid|test)$/i;
|
||||
|
||||
const ipv4Parts = (hostname: string) => {
|
||||
const parts = hostname.split('.').map(Number);
|
||||
if (parts.length !== 4 || parts.some((part) => !Number.isInteger(part) || part < 0 || part > 255)) {
|
||||
return null;
|
||||
}
|
||||
return parts;
|
||||
};
|
||||
|
||||
const isReservedIpv4 = (parts: number[]) => {
|
||||
return parts[0] === 0
|
||||
|| parts[0] === 10
|
||||
|| parts[0] === 127
|
||||
|| (parts[0] === 100 && parts[1] >= 64 && parts[1] <= 127)
|
||||
|| (parts[0] === 169 && parts[1] === 254)
|
||||
|| (parts[0] === 172 && parts[1] >= 16 && parts[1] <= 31)
|
||||
|| (parts[0] === 192 && parts[1] === 168)
|
||||
|| (parts[0] === 192 && parts[1] === 0 && (parts[2] === 0 || parts[2] === 2))
|
||||
|| (parts[0] === 198 && (parts[1] === 18 || parts[1] === 19))
|
||||
|| (parts[0] === 198 && parts[1] === 51 && parts[2] === 100)
|
||||
|| (parts[0] === 203 && parts[1] === 0 && parts[2] === 113)
|
||||
|| parts[0] >= 224;
|
||||
};
|
||||
|
||||
const normalizePublicHttpsUrl = (rawValue?: string) => {
|
||||
const value = String(rawValue || '').trim();
|
||||
if (!value || placeholderPattern.test(value)) return '';
|
||||
if (/[\u0000-\u0020\u007f]/.test(value)) return '';
|
||||
|
||||
const match = /^https:\/\/([^/?#]+)(?:[/?#]|$)/i.exec(value);
|
||||
if (!match || match[1].includes('@')) return '';
|
||||
const authority = match[1];
|
||||
let hostname = '';
|
||||
if (authority.startsWith('[')) {
|
||||
const end = authority.indexOf(']');
|
||||
if (end <= 1 || (authority.slice(end + 1) && !/^:\d+$/.test(authority.slice(end + 1)))) return '';
|
||||
hostname = authority.slice(1, end).toLowerCase();
|
||||
} else {
|
||||
const hostAndPort = authority.toLowerCase();
|
||||
const colon = hostAndPort.lastIndexOf(':');
|
||||
if (colon >= 0) {
|
||||
if (!/^\d+$/.test(hostAndPort.slice(colon + 1)) || hostAndPort.slice(0, colon).includes(':')) return '';
|
||||
hostname = hostAndPort.slice(0, colon);
|
||||
} else {
|
||||
hostname = hostAndPort;
|
||||
}
|
||||
}
|
||||
|
||||
const numericIpv4 = /^[0-9.]+$/.test(hostname);
|
||||
const parsedIpv4 = numericIpv4 ? ipv4Parts(hostname) : null;
|
||||
if (
|
||||
!hostname
|
||||
|| reservedHostnamePattern.test(hostname)
|
||||
|| hostname === 'localhost'
|
||||
|| hostname.endsWith('.localhost')
|
||||
|| hostname === '::1'
|
||||
|| (numericIpv4 && (!parsedIpv4 || isReservedIpv4(parsedIpv4)))
|
||||
|| (hostname.includes(':') && (!/^[0-9a-f:]+$/i.test(hostname) || /^f[cd]/.test(hostname) || hostname.startsWith('fe80:')))
|
||||
|| (!numericIpv4 && !hostname.includes(':') && (
|
||||
!hostname.includes('.')
|
||||
|| !/^[a-z0-9.-]+$/i.test(hostname)
|
||||
|| hostname.startsWith('.')
|
||||
|| hostname.endsWith('.')
|
||||
))
|
||||
) return '';
|
||||
return value;
|
||||
};
|
||||
|
||||
const termsUrl = normalizePublicHttpsUrl(import.meta.env.VITE_APP_TERMS_URL);
|
||||
const privacyUrl = normalizePublicHttpsUrl(import.meta.env.VITE_APP_PRIVACY_URL);
|
||||
|
||||
export const legalLinksReady = Boolean(termsUrl && privacyUrl && termsUrl !== privacyUrl);
|
||||
|
||||
export const legalDocumentUrl = (kind: LegalDocumentKind) => {
|
||||
if (!legalLinksReady) return '';
|
||||
return kind === 'terms' ? termsUrl : privacyUrl;
|
||||
};
|
||||
Reference in New Issue
Block a user