issue/910: Fix CORS warning for localhost (#939)

See maplibre/maputnik#910

As per the issue, test the hostname of the for a localhost URL, by
1. Domain - localhost
2. IPv4 localhost subnet - 127.0.0.1/8
3. IPv6 localhost - [::1]

## Launch Checklist

<!-- Thanks for the PR! Feel free to add or remove items from the
checklist. -->


 - [x] Briefly describe the changes in this PR.
 - [x] Link to related issues.
- [x] Include before/after visuals or gifs if this PR includes visual
changes.
 - [x] Write tests for all new functionality.
 - [x] Add an entry to `CHANGELOG.md` under the `## main` section.

---------

Co-authored-by: zstadler <zeev.stadler@gmail.com>
Co-authored-by: Harel M <harel.mazor@gmail.com>
Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
This commit is contained in:
John Bayly
2025-11-09 21:57:05 +00:00
committed by GitHub
parent 876a3d70df
commit 7a93d592ff
4 changed files with 216 additions and 44 deletions

View File

@@ -3,55 +3,31 @@ import InputString from "./InputString";
import SmallError from "./SmallError";
import { Trans, type WithTranslation, withTranslation } from "react-i18next";
import { type TFunction } from "i18next";
import { ErrorType, validate } from "../libs/urlopen";
function validate(url: string, t: TFunction): JSX.Element | undefined {
if (url === "") {
return;
}
let error;
const getProtocol = (url: string) => {
try {
const urlObj = new URL(url);
return urlObj.protocol;
}
catch (_err) {
return undefined;
}
};
const protocol = getProtocol(url);
const isSsl = window.location.protocol === "https:";
if (!protocol) {
if (isSsl) {
error = (
function errorTypeToJsx(errorType: ErrorType | undefined, t: TFunction): JSX.Element | undefined {
switch (errorType) {
case ErrorType.EmptyHttpsProtocol:
return (
<SmallError>
<Trans t={t}>Must provide protocol: <code>https://</code></Trans>
</SmallError>
);
} else {
error = (
case ErrorType.EmptyHttpOrHttpsProtocol:
return (
<SmallError>
<Trans t={t}>Must provide protocol: <code>http://</code> or <code>https://</code></Trans>
</SmallError>
);
}
case ErrorType.CorsError:
return (
<SmallError>
<Trans t={t}>CORS policy won&apos;t allow fetching resources served over http from https, use a <code>https://</code> domain</Trans>
</SmallError>
);
default:
return undefined;
}
else if (
protocol &&
protocol === "http:" &&
window.location.protocol === "https:"
) {
error = (
<SmallError>
<Trans t={t}>
CORS policy won&apos;t allow fetching resources served over http from https, use a <code>https://</code> domain
</Trans>
</SmallError>
);
}
return error;
}
export type FieldUrlProps = {
@@ -71,7 +47,7 @@ export type FieldUrlProps = {
type InputUrlInternalProps = FieldUrlProps & WithTranslation;
type InputUrlState = {
error?: React.ReactNode
error?: ErrorType
};
class InputUrlInternal extends React.Component<InputUrlInternalProps, InputUrlState> {
@@ -82,20 +58,20 @@ class InputUrlInternal extends React.Component<InputUrlInternalProps, InputUrlSt
constructor (props: InputUrlInternalProps) {
super(props);
this.state = {
error: validate(props.value, props.t),
error: validate(props.value),
};
}
onInput = (url: string) => {
this.setState({
error: validate(url, this.props.t),
error: validate(url),
});
if (this.props.onInput) this.props.onInput(url);
};
onChange = (url: string) => {
this.setState({
error: validate(url, this.props.t),
error: validate(url),
});
this.props.onChange(url);
};
@@ -109,7 +85,7 @@ class InputUrlInternal extends React.Component<InputUrlInternalProps, InputUrlSt
onChange={this.onChange}
aria-label={this.props["aria-label"]}
/>
{this.state.error}
{errorTypeToJsx(this.state.error, this.props.t)}
</div>
);
}