mirror of
https://github.com/prymitive/karma
synced 2026-05-05 03:16:51 +00:00
Merge pull request #1159 from prymitive/get-no-cors
fix(ui): use mode:no-cors for fetch GET requests
This commit is contained in:
@@ -1,9 +1,28 @@
|
||||
import merge from "lodash.merge";
|
||||
|
||||
const FetchWithCredentials = async (uri, options) =>
|
||||
const CommonOptions = {
|
||||
credentials: "include",
|
||||
redirect: "follow"
|
||||
};
|
||||
|
||||
const FetchGet = async (uri, options) =>
|
||||
await fetch(
|
||||
uri,
|
||||
merge({}, { credentials: "include", redirect: "follow" }, options)
|
||||
merge(
|
||||
{},
|
||||
{
|
||||
method: "GET",
|
||||
mode: "no-cors"
|
||||
},
|
||||
CommonOptions,
|
||||
options
|
||||
)
|
||||
);
|
||||
|
||||
export { FetchWithCredentials };
|
||||
const FetchPost = async (uri, options) =>
|
||||
await fetch(uri, merge({}, { method: "POST" }, CommonOptions, options));
|
||||
|
||||
const FetchDelete = async (uri, options) =>
|
||||
await fetch(uri, merge({}, { method: "DELETE" }, CommonOptions, options));
|
||||
|
||||
export { CommonOptions, FetchGet, FetchPost, FetchDelete };
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
import { FetchWithCredentials } from "./Fetch";
|
||||
import { CommonOptions, FetchGet, FetchPost, FetchDelete } from "./Fetch";
|
||||
|
||||
import merge from "lodash.merge";
|
||||
|
||||
beforeEach(() => {
|
||||
fetch.resetMocks();
|
||||
@@ -8,37 +10,53 @@ afterEach(() => {
|
||||
jest.restoreAllMocks();
|
||||
});
|
||||
|
||||
describe("FetchWithCredentials", () => {
|
||||
it("fetch passes '{credentials: include}' to all requests", async () => {
|
||||
const request = FetchWithCredentials("http://example.com", {});
|
||||
await expect(request).resolves.toBeUndefined();
|
||||
expect(fetch).toHaveBeenCalledWith("http://example.com", {
|
||||
credentials: "include",
|
||||
redirect: "follow"
|
||||
});
|
||||
});
|
||||
describe("Fetch", () => {
|
||||
const tests = {
|
||||
FetchGet: FetchGet,
|
||||
FetchPost: FetchPost,
|
||||
FetchDelete: FetchDelete
|
||||
};
|
||||
|
||||
it("custom keys are merged with defaults", async () => {
|
||||
const request = FetchWithCredentials("http://example.com", {
|
||||
foo: "bar"
|
||||
});
|
||||
await expect(request).resolves.toBeUndefined();
|
||||
expect(fetch).toHaveBeenCalledWith("http://example.com", {
|
||||
credentials: "include",
|
||||
redirect: "follow",
|
||||
foo: "bar"
|
||||
});
|
||||
});
|
||||
const methodOptions = {
|
||||
FetchGet: { method: "GET", mode: "no-cors" },
|
||||
FetchPost: { method: "POST" },
|
||||
FetchDelete: { method: "DELETE" }
|
||||
};
|
||||
|
||||
it("custom credentials are used when passed", async () => {
|
||||
const request = FetchWithCredentials("http://example.com", {
|
||||
credentials: "none",
|
||||
redirect: "follow"
|
||||
for (const [name, func] of Object.entries(tests)) {
|
||||
it(`${name}: passes '{credentials: include}' to all requests`, async () => {
|
||||
const request = func("http://example.com", {});
|
||||
await expect(request).resolves.toBeUndefined();
|
||||
expect(fetch).toHaveBeenCalledWith(
|
||||
"http://example.com",
|
||||
merge({}, CommonOptions, methodOptions[name])
|
||||
);
|
||||
});
|
||||
await expect(request).resolves.toBeUndefined();
|
||||
expect(fetch).toHaveBeenCalledWith("http://example.com", {
|
||||
credentials: "none",
|
||||
redirect: "follow"
|
||||
|
||||
it(`${name}: custom keys are merged with defaults`, async () => {
|
||||
const request = func("http://example.com", {
|
||||
foo: "bar"
|
||||
});
|
||||
await expect(request).resolves.toBeUndefined();
|
||||
expect(fetch).toHaveBeenCalledWith(
|
||||
"http://example.com",
|
||||
merge({}, CommonOptions, methodOptions[name], { foo: "bar" })
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
it(`${name}: custom credentials are used when passed`, async () => {
|
||||
const request = func("http://example.com", {
|
||||
credentials: "none",
|
||||
redirect: "follow"
|
||||
});
|
||||
await expect(request).resolves.toBeUndefined();
|
||||
expect(fetch).toHaveBeenCalledWith(
|
||||
"http://example.com",
|
||||
merge({}, CommonOptions, methodOptions[name], {
|
||||
credentials: "none",
|
||||
redirect: "follow"
|
||||
})
|
||||
);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
@@ -21,7 +21,7 @@ import {
|
||||
MatchersFromGroup,
|
||||
GenerateAlertmanagerSilenceData
|
||||
} from "Stores/SilenceFormStore";
|
||||
import { FetchWithCredentials } from "Common/Fetch";
|
||||
import { FetchPost } from "Common/Fetch";
|
||||
import { TooltipWrapper } from "Components/TooltipWrapper";
|
||||
|
||||
const SubmitState = Object.freeze({
|
||||
@@ -148,19 +148,15 @@ const AlertAck = observer(
|
||||
? `${am.uri}/api/v2/silences`
|
||||
: `${am.uri}/api/v1/silences`;
|
||||
|
||||
this.submitState.silencesByCluster[cluster].fetch = FetchWithCredentials(
|
||||
uri,
|
||||
{
|
||||
method: "POST",
|
||||
body: JSON.stringify(
|
||||
this.submitState.silencesByCluster[cluster].payload
|
||||
),
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
...am.headers
|
||||
}
|
||||
this.submitState.silencesByCluster[cluster].fetch = FetchPost(uri, {
|
||||
body: JSON.stringify(
|
||||
this.submitState.silencesByCluster[cluster].payload
|
||||
),
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
...am.headers
|
||||
}
|
||||
)
|
||||
})
|
||||
.then(result => {
|
||||
if (isOpenAPI) {
|
||||
if (result.ok) {
|
||||
|
||||
@@ -7,7 +7,7 @@ import { observer } from "mobx-react";
|
||||
import Creatable from "react-select/creatable";
|
||||
|
||||
import { StaticLabels } from "Common/Query";
|
||||
import { FetchWithCredentials } from "Common/Fetch";
|
||||
import { FetchGet } from "Common/Fetch";
|
||||
import { FormatBackendURI } from "Stores/AlertStore";
|
||||
import { Settings } from "Stores/Settings";
|
||||
import { ReactSelectStyles } from "Components/MultiSelect";
|
||||
@@ -34,7 +34,7 @@ const SortLabelName = observer(
|
||||
});
|
||||
|
||||
populateNameSuggestions = action(() => {
|
||||
this.nameSuggestionsFetch = FetchWithCredentials(
|
||||
this.nameSuggestionsFetch = FetchGet(
|
||||
FormatBackendURI(`labelNames.json`),
|
||||
{}
|
||||
)
|
||||
|
||||
@@ -16,7 +16,7 @@ import { APISilence } from "Models/API";
|
||||
import { AlertStore, FormatBackendURI, FormatAlertsQ } from "Stores/AlertStore";
|
||||
import { SilenceFormStore } from "Stores/SilenceFormStore";
|
||||
import { FormatQuery, QueryOperators, StaticLabels } from "Common/Query";
|
||||
import { FetchWithCredentials } from "Common/Fetch";
|
||||
import { FetchGet, FetchDelete } from "Common/Fetch";
|
||||
import { Modal } from "Components/Modal";
|
||||
import {
|
||||
LabelSetList,
|
||||
@@ -144,7 +144,7 @@ const DeleteSilenceModalContent = observer(
|
||||
FormatQuery(StaticLabels.SilenceID, QueryOperators.Equal, silence.id)
|
||||
]);
|
||||
|
||||
this.previewState.fetch = FetchWithCredentials(alertsURI, {})
|
||||
this.previewState.fetch = FetchGet(alertsURI, {})
|
||||
.then(result => result.json())
|
||||
.then(result => {
|
||||
this.previewState.groupsToUniqueLabels(Object.values(result.groups));
|
||||
@@ -175,8 +175,7 @@ const DeleteSilenceModalContent = observer(
|
||||
? `${alertmanager.uri}/api/v2/silence/${silence.id}`
|
||||
: `${alertmanager.uri}/api/v1/silence/${silence.id}`;
|
||||
|
||||
this.deleteState.fetch = FetchWithCredentials(uri, {
|
||||
method: "DELETE",
|
||||
this.deleteState.fetch = FetchDelete(uri, {
|
||||
headers: alertmanager.headers
|
||||
})
|
||||
.then(result => {
|
||||
|
||||
@@ -15,7 +15,7 @@ import { faSearch } from "@fortawesome/free-solid-svg-icons/faSearch";
|
||||
import { AlertStore, FormatBackendURI } from "Stores/AlertStore";
|
||||
import { Settings } from "Stores/Settings";
|
||||
import { IsMobile } from "Common/Device";
|
||||
import { FetchWithCredentials } from "Common/Fetch";
|
||||
import { FetchGet } from "Common/Fetch";
|
||||
import { FilterInputLabel } from "Components/Labels/FilterInputLabel";
|
||||
import { AutosuggestTheme } from "./Constants";
|
||||
import { History } from "./History";
|
||||
@@ -73,7 +73,7 @@ const FilterInput = observer(
|
||||
onSuggestionsFetchRequested = debounce(
|
||||
action(({ value }) => {
|
||||
if (value !== "") {
|
||||
this.inputStore.suggestionsFetch = FetchWithCredentials(
|
||||
this.inputStore.suggestionsFetch = FetchGet(
|
||||
FormatBackendURI(`autocomplete.json?term=${value}`),
|
||||
{}
|
||||
)
|
||||
|
||||
@@ -21,7 +21,7 @@ import { faAngleDoubleRight } from "@fortawesome/free-solid-svg-icons/faAngleDou
|
||||
import { AlertStore, FormatBackendURI } from "Stores/AlertStore";
|
||||
import { SilenceFormStore } from "Stores/SilenceFormStore";
|
||||
import { Settings } from "Stores/Settings";
|
||||
import { FetchWithCredentials } from "Common/Fetch";
|
||||
import { FetchGet } from "Common/Fetch";
|
||||
import { MountFade } from "Components/Animations/MountFade";
|
||||
import { ManagedSilence } from "Components/ManagedSilence";
|
||||
|
||||
@@ -102,7 +102,7 @@ const Browser = observer(
|
||||
}`
|
||||
);
|
||||
|
||||
this.dataSource.fetch = FetchWithCredentials(uri, {})
|
||||
this.dataSource.fetch = FetchGet(uri, {})
|
||||
.then(result => {
|
||||
return result.json();
|
||||
})
|
||||
|
||||
@@ -8,7 +8,7 @@ import { SilenceFormMatcher } from "Models/SilenceForm";
|
||||
import { MultiSelect } from "Components/MultiSelect";
|
||||
import { ValidationError } from "Components/MultiSelect/ValidationError";
|
||||
import { FormatBackendURI } from "Stores/AlertStore";
|
||||
import { FetchWithCredentials } from "Common/Fetch";
|
||||
import { FetchGet } from "Common/Fetch";
|
||||
|
||||
const LabelNameInput = observer(
|
||||
class LabelNameInput extends MultiSelect {
|
||||
@@ -20,7 +20,7 @@ const LabelNameInput = observer(
|
||||
populateNameSuggestions = action(() => {
|
||||
const { matcher } = this.props;
|
||||
|
||||
this.nameSuggestionsFetch = FetchWithCredentials(
|
||||
this.nameSuggestionsFetch = FetchGet(
|
||||
FormatBackendURI(`labelNames.json`),
|
||||
{}
|
||||
)
|
||||
@@ -45,7 +45,7 @@ const LabelNameInput = observer(
|
||||
populateValueSuggestions = action(() => {
|
||||
const { matcher } = this.props;
|
||||
|
||||
this.valueSuggestionsFetch = FetchWithCredentials(
|
||||
this.valueSuggestionsFetch = FetchGet(
|
||||
FormatBackendURI(`labelValues.json?name=${matcher.name}`),
|
||||
{}
|
||||
)
|
||||
|
||||
@@ -14,7 +14,7 @@ import { FormatBackendURI, FormatAlertsQ } from "Stores/AlertStore";
|
||||
import { SilenceFormStore } from "Stores/SilenceFormStore";
|
||||
import { SilenceFormMatcher } from "Models/SilenceForm";
|
||||
import { TooltipWrapper } from "Components/TooltipWrapper";
|
||||
import { FetchWithCredentials } from "Common/Fetch";
|
||||
import { FetchGet } from "Common/Fetch";
|
||||
import { MatcherToFilter, AlertManagersToFilter } from "../Matchers";
|
||||
|
||||
const MatchCounter = observer(
|
||||
@@ -55,7 +55,7 @@ const MatchCounter = observer(
|
||||
const alertsURI =
|
||||
FormatBackendURI("alerts.json?") + FormatAlertsQ(filters);
|
||||
|
||||
this.matchedAlerts.fetch = FetchWithCredentials(alertsURI, {})
|
||||
this.matchedAlerts.fetch = FetchGet(alertsURI, {})
|
||||
.then(result => {
|
||||
return result.json();
|
||||
})
|
||||
|
||||
@@ -16,7 +16,7 @@ import {
|
||||
LabelSetList,
|
||||
GroupListToUniqueLabelsList
|
||||
} from "Components/LabelSetList";
|
||||
import { FetchWithCredentials } from "Common/Fetch";
|
||||
import { FetchGet } from "Common/Fetch";
|
||||
import { MatcherToFilter, AlertManagersToFilter } from "../Matchers";
|
||||
|
||||
const FetchError = ({ message }) => (
|
||||
@@ -82,7 +82,7 @@ const SilencePreview = observer(
|
||||
const alertsURI =
|
||||
FormatBackendURI("alerts.json?") + FormatAlertsQ(filters);
|
||||
|
||||
this.matchedAlerts.fetch = FetchWithCredentials(alertsURI, {})
|
||||
this.matchedAlerts.fetch = FetchGet(alertsURI, {})
|
||||
.then(result => {
|
||||
return result.json();
|
||||
})
|
||||
|
||||
@@ -85,11 +85,14 @@ describe("<SilencePreview />", () => {
|
||||
|
||||
const tree = MountedSilencePreview();
|
||||
await expect(tree.instance().matchedAlerts.fetch).resolves.toBeUndefined();
|
||||
expect(
|
||||
fetch
|
||||
).toHaveBeenCalledWith(
|
||||
expect(fetch).toHaveBeenCalledWith(
|
||||
"./alerts.json?q=foo%3Dbar&q=%40alertmanager%3D~%5E%28amValue%29%24",
|
||||
{ credentials: "include", redirect: "follow" }
|
||||
{
|
||||
method: "GET",
|
||||
mode: "no-cors",
|
||||
credentials: "include",
|
||||
redirect: "follow"
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
@@ -101,11 +104,14 @@ describe("<SilencePreview />", () => {
|
||||
|
||||
const tree = MountedSilencePreview();
|
||||
await expect(tree.instance().matchedAlerts.fetch).resolves.toBeUndefined();
|
||||
expect(
|
||||
fetch
|
||||
).toHaveBeenCalledWith(
|
||||
expect(fetch).toHaveBeenCalledWith(
|
||||
"./alerts.json?q=foo%3Dbar&q=%40alertmanager%3D~%5E%28am1%7Cam2%29%24",
|
||||
{ credentials: "include", redirect: "follow" }
|
||||
{
|
||||
method: "GET",
|
||||
mode: "no-cors",
|
||||
credentials: "include",
|
||||
redirect: "follow"
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
|
||||
@@ -13,7 +13,7 @@ import { faExclamationCircle } from "@fortawesome/free-solid-svg-icons/faExclama
|
||||
|
||||
import { APISilenceMatcher } from "Models/API";
|
||||
import { AlertStore } from "Stores/AlertStore";
|
||||
import { FetchWithCredentials } from "Common/Fetch";
|
||||
import { FetchPost } from "Common/Fetch";
|
||||
|
||||
const SubmitState = Object.freeze({
|
||||
InProgress: "InProgress",
|
||||
@@ -109,8 +109,7 @@ const SilenceSubmitProgress = observer(
|
||||
? `${am.uri}/api/v2/silences`
|
||||
: `${am.uri}/api/v1/silences`;
|
||||
|
||||
this.submitState.fetch = FetchWithCredentials(uri, {
|
||||
method: "POST",
|
||||
this.submitState.fetch = FetchPost(uri, {
|
||||
body: JSON.stringify(payload),
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
|
||||
@@ -8,7 +8,7 @@ import qs from "qs";
|
||||
|
||||
import moment from "moment";
|
||||
|
||||
import { FetchWithCredentials } from "Common/Fetch";
|
||||
import { FetchGet } from "Common/Fetch";
|
||||
|
||||
const QueryStringEncodeOptions = {
|
||||
encodeValuesOnly: true, // don't encode q[]
|
||||
@@ -268,7 +268,7 @@ class AlertStore {
|
||||
`alerts.json?sortOrder=${sortOrder}&sortLabel=${sortLabel}&sortReverse=${sortReverse}&`
|
||||
) + FormatAPIFilterQuery(this.filters.values.map(f => f.raw));
|
||||
|
||||
return FetchWithCredentials(alertsURI, {})
|
||||
return FetchGet(alertsURI, {})
|
||||
.then(result => {
|
||||
this.status.setProcessing();
|
||||
return result.json();
|
||||
|
||||
Reference in New Issue
Block a user