feat: add support for HAWK authentication (#4694)
Co-authored-by: jamesgeorge007 <25279263+jamesgeorge007@users.noreply.github.com>
This commit is contained in:
parent
cccd711507
commit
ccf3c6f834
24 changed files with 709 additions and 50 deletions
|
|
@ -483,6 +483,24 @@ describe("hopp test [options] <file_path_or_id>", { timeout: 100000 }, () => {
|
||||||
|
|
||||||
expect(error).toBeTruthy();
|
expect(error).toBeTruthy();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe("HAWK Authentication", () => {
|
||||||
|
test("Correctly generates and attaches authorization headers to the request ", async () => {
|
||||||
|
const COLL_PATH = getTestJsonFilePath(
|
||||||
|
"hawk-auth-success-coll.json",
|
||||||
|
"collection"
|
||||||
|
);
|
||||||
|
const ENV_PATH = getTestJsonFilePath(
|
||||||
|
"hawk-auth-envs.json",
|
||||||
|
"environment"
|
||||||
|
);
|
||||||
|
|
||||||
|
const args = `test ${COLL_PATH} -e ${ENV_PATH}`;
|
||||||
|
const { error } = await runCLI(args);
|
||||||
|
|
||||||
|
expect(error).toBeNull();
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("Test `hopp test <file_path_or_id> --delay <delay_in_ms>` command:", () => {
|
describe("Test `hopp test <file_path_or_id> --delay <delay_in_ms>` command:", () => {
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,43 @@
|
||||||
|
{
|
||||||
|
"v": 3,
|
||||||
|
"name": "HAWK Auth (success state) - collection",
|
||||||
|
"folders": [],
|
||||||
|
"requests": [
|
||||||
|
{
|
||||||
|
"v": "12",
|
||||||
|
"id": "cm0dm70cw000687bnxi830zz2",
|
||||||
|
"auth": {
|
||||||
|
"authType": "hawk",
|
||||||
|
"authActive": true,
|
||||||
|
"authId": "<<id>>",
|
||||||
|
"authKey": "<<key>>",
|
||||||
|
"algorithm": "<<algorithm>>",
|
||||||
|
"includePayloadHash": false,
|
||||||
|
"user": "<<user>>",
|
||||||
|
"nonce": "<<nonce>>",
|
||||||
|
"ext": "<<ext>>",
|
||||||
|
"app": "<<app>>",
|
||||||
|
"dlg": "<<dlg>>",
|
||||||
|
"timestamp": "<<timestamp>>"
|
||||||
|
},
|
||||||
|
"body": {
|
||||||
|
"body": null,
|
||||||
|
"contentType": null
|
||||||
|
},
|
||||||
|
"name": "hawk-auth-headers",
|
||||||
|
"method": "GET",
|
||||||
|
"params": [],
|
||||||
|
"headers": [],
|
||||||
|
"endpoint": "<<url>>",
|
||||||
|
"testScript": "pw.test(\"Status code is 200\", ()=> { pw.expect(pw.response.status).toBe(200);});",
|
||||||
|
"preRequestScript": "",
|
||||||
|
"responses": {},
|
||||||
|
"requestVariables": []
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"auth": {
|
||||||
|
"authType": "inherit",
|
||||||
|
"authActive": true
|
||||||
|
},
|
||||||
|
"headers": []
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,47 @@
|
||||||
|
{
|
||||||
|
"v": 1,
|
||||||
|
"id": "cm0dsn3v70004p4qk3l9b7sjm",
|
||||||
|
"name": "HAWK Auth - environments",
|
||||||
|
"variables": [
|
||||||
|
{
|
||||||
|
"key": "url",
|
||||||
|
"value": "https://postman-echo.com/auth/hawk"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "id",
|
||||||
|
"value": "dh37fgj492je"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "key",
|
||||||
|
"value": "werxhqb98rpaxn39848xrunpaw3489ruxnpa98w4rxn"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "algorithm",
|
||||||
|
"value": "sha256"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "user",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "nonce",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "ext",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "app",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "dlg",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "timestamp",
|
||||||
|
"value": ""
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
@ -485,17 +485,17 @@ export const WORKSPACE_MULTIPLE_CHILD_COLLECTIONS_WITH_AUTH_HEADERS_MOCK: Worksp
|
||||||
export const TRANSFORMED_MULTIPLE_CHILD_COLLECTIONS_WITH_AUTH_HEADERS_MOCK: HoppCollection[] =
|
export const TRANSFORMED_MULTIPLE_CHILD_COLLECTIONS_WITH_AUTH_HEADERS_MOCK: HoppCollection[] =
|
||||||
[
|
[
|
||||||
{
|
{
|
||||||
v: 6,
|
v: 7,
|
||||||
id: "clx1f86hv000010f8szcfya0t",
|
id: "clx1f86hv000010f8szcfya0t",
|
||||||
name: "Multiple child collections with authorization & headers set at each level",
|
name: "Multiple child collections with authorization & headers set at each level",
|
||||||
folders: [
|
folders: [
|
||||||
{
|
{
|
||||||
v: 6,
|
v: 7,
|
||||||
id: "clx1fjgah000110f8a5bs68gd",
|
id: "clx1fjgah000110f8a5bs68gd",
|
||||||
name: "folder-1",
|
name: "folder-1",
|
||||||
folders: [
|
folders: [
|
||||||
{
|
{
|
||||||
v: 6,
|
v: 7,
|
||||||
id: "clx1fjwmm000410f8l1gkkr1a",
|
id: "clx1fjwmm000410f8l1gkkr1a",
|
||||||
name: "folder-11",
|
name: "folder-11",
|
||||||
folders: [],
|
folders: [],
|
||||||
|
|
@ -537,7 +537,7 @@ export const TRANSFORMED_MULTIPLE_CHILD_COLLECTIONS_WITH_AUTH_HEADERS_MOCK: Hopp
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
v: 6,
|
v: 7,
|
||||||
id: "clx1fjyxm000510f8pv90dt43",
|
id: "clx1fjyxm000510f8pv90dt43",
|
||||||
name: "folder-12",
|
name: "folder-12",
|
||||||
folders: [],
|
folders: [],
|
||||||
|
|
@ -595,7 +595,7 @@ export const TRANSFORMED_MULTIPLE_CHILD_COLLECTIONS_WITH_AUTH_HEADERS_MOCK: Hopp
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
v: 6,
|
v: 7,
|
||||||
id: "clx1fk1cv000610f88kc3aupy",
|
id: "clx1fk1cv000610f88kc3aupy",
|
||||||
name: "folder-13",
|
name: "folder-13",
|
||||||
folders: [],
|
folders: [],
|
||||||
|
|
@ -707,12 +707,12 @@ export const TRANSFORMED_MULTIPLE_CHILD_COLLECTIONS_WITH_AUTH_HEADERS_MOCK: Hopp
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
v: 6,
|
v: 7,
|
||||||
id: "clx1fjk9o000210f8j0573pls",
|
id: "clx1fjk9o000210f8j0573pls",
|
||||||
name: "folder-2",
|
name: "folder-2",
|
||||||
folders: [
|
folders: [
|
||||||
{
|
{
|
||||||
v: 6,
|
v: 7,
|
||||||
id: "clx1fk516000710f87sfpw6bo",
|
id: "clx1fk516000710f87sfpw6bo",
|
||||||
name: "folder-21",
|
name: "folder-21",
|
||||||
folders: [],
|
folders: [],
|
||||||
|
|
@ -752,7 +752,7 @@ export const TRANSFORMED_MULTIPLE_CHILD_COLLECTIONS_WITH_AUTH_HEADERS_MOCK: Hopp
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
v: 6,
|
v: 7,
|
||||||
id: "clx1fk72t000810f8gfwkpi5y",
|
id: "clx1fk72t000810f8gfwkpi5y",
|
||||||
name: "folder-22",
|
name: "folder-22",
|
||||||
folders: [],
|
folders: [],
|
||||||
|
|
@ -810,7 +810,7 @@ export const TRANSFORMED_MULTIPLE_CHILD_COLLECTIONS_WITH_AUTH_HEADERS_MOCK: Hopp
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
v: 6,
|
v: 7,
|
||||||
id: "clx1fk95g000910f8bunhaoo8",
|
id: "clx1fk95g000910f8bunhaoo8",
|
||||||
name: "folder-23",
|
name: "folder-23",
|
||||||
folders: [],
|
folders: [],
|
||||||
|
|
@ -915,12 +915,12 @@ export const TRANSFORMED_MULTIPLE_CHILD_COLLECTIONS_WITH_AUTH_HEADERS_MOCK: Hopp
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
v: 6,
|
v: 7,
|
||||||
id: "clx1fjmlq000310f86o4d3w2o",
|
id: "clx1fjmlq000310f86o4d3w2o",
|
||||||
name: "folder-3",
|
name: "folder-3",
|
||||||
folders: [
|
folders: [
|
||||||
{
|
{
|
||||||
v: 6,
|
v: 7,
|
||||||
id: "clx1iwq0p003e10f8u8zg0p85",
|
id: "clx1iwq0p003e10f8u8zg0p85",
|
||||||
name: "folder-31",
|
name: "folder-31",
|
||||||
folders: [],
|
folders: [],
|
||||||
|
|
@ -960,7 +960,7 @@ export const TRANSFORMED_MULTIPLE_CHILD_COLLECTIONS_WITH_AUTH_HEADERS_MOCK: Hopp
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
v: 6,
|
v: 7,
|
||||||
id: "clx1izut7003m10f894ip59zg",
|
id: "clx1izut7003m10f894ip59zg",
|
||||||
name: "folder-32",
|
name: "folder-32",
|
||||||
folders: [],
|
folders: [],
|
||||||
|
|
@ -1018,7 +1018,7 @@ export const TRANSFORMED_MULTIPLE_CHILD_COLLECTIONS_WITH_AUTH_HEADERS_MOCK: Hopp
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
v: 6,
|
v: 7,
|
||||||
id: "clx1j2ka9003q10f8cdbzpgpg",
|
id: "clx1j2ka9003q10f8cdbzpgpg",
|
||||||
name: "folder-33",
|
name: "folder-33",
|
||||||
folders: [],
|
folders: [],
|
||||||
|
|
|
||||||
|
|
@ -32,6 +32,8 @@ import {
|
||||||
generateDigestAuthHeader,
|
generateDigestAuthHeader,
|
||||||
} from "./auth/digest";
|
} from "./auth/digest";
|
||||||
|
|
||||||
|
import { calculateHawkHeader } from "@hoppscotch/data";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Runs pre-request-script runner over given request which extracts set ENVs and
|
* Runs pre-request-script runner over given request which extracts set ENVs and
|
||||||
* applies them on current request to generate updated request.
|
* applies them on current request to generate updated request.
|
||||||
|
|
@ -287,6 +289,44 @@ export async function getEffectiveRESTRequest(
|
||||||
value: authHeaderValue,
|
value: authHeaderValue,
|
||||||
description: "",
|
description: "",
|
||||||
});
|
});
|
||||||
|
} else if (request.auth.authType === "hawk") {
|
||||||
|
const { method, endpoint } = request;
|
||||||
|
|
||||||
|
const hawkHeader = await calculateHawkHeader({
|
||||||
|
url: parseTemplateString(endpoint, resolvedVariables), // URL
|
||||||
|
method: method, // HTTP method
|
||||||
|
id: parseTemplateString(request.auth.authId, resolvedVariables),
|
||||||
|
key: parseTemplateString(request.auth.authKey, resolvedVariables),
|
||||||
|
algorithm: request.auth.algorithm,
|
||||||
|
|
||||||
|
// advanced parameters (optional)
|
||||||
|
includePayloadHash: request.auth.includePayloadHash,
|
||||||
|
nonce: request.auth.nonce
|
||||||
|
? parseTemplateString(request.auth.nonce, resolvedVariables)
|
||||||
|
: undefined,
|
||||||
|
ext: request.auth.ext
|
||||||
|
? parseTemplateString(request.auth.ext, resolvedVariables)
|
||||||
|
: undefined,
|
||||||
|
app: request.auth.app
|
||||||
|
? parseTemplateString(request.auth.app, resolvedVariables)
|
||||||
|
: undefined,
|
||||||
|
dlg: request.auth.dlg
|
||||||
|
? parseTemplateString(request.auth.dlg, resolvedVariables)
|
||||||
|
: undefined,
|
||||||
|
timestamp: request.auth.timestamp
|
||||||
|
? parseInt(
|
||||||
|
parseTemplateString(request.auth.timestamp, resolvedVariables),
|
||||||
|
10
|
||||||
|
)
|
||||||
|
: undefined,
|
||||||
|
});
|
||||||
|
|
||||||
|
effectiveFinalHeaders.push({
|
||||||
|
active: true,
|
||||||
|
key: "Authorization",
|
||||||
|
value: hawkHeader,
|
||||||
|
description: "",
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -680,7 +680,8 @@
|
||||||
"localaccess_unsupported": "Current interceptor does not support local access, please consider using Agent, Extension interceptors or the Desktop App"
|
"localaccess_unsupported": "Current interceptor does not support local access, please consider using Agent, Extension interceptors or the Desktop App"
|
||||||
},
|
},
|
||||||
"auth": {
|
"auth": {
|
||||||
"digest": "Agent interceptor or the Hoppscotch Desktop app are recommended when using Digest Authorization."
|
"digest": "Agent interceptor or the Hoppscotch Desktop app are recommended when using Digest Authorization.",
|
||||||
|
"hawk": "Agent interceptor or the Hoppscotch Desktop app are recommended when using Hawk Authorization."
|
||||||
},
|
},
|
||||||
"body": {
|
"body": {
|
||||||
"binary": "Sending binary data via the current interceptor is not supported yet."
|
"binary": "Sending binary data via the current interceptor is not supported yet."
|
||||||
|
|
|
||||||
|
|
@ -48,6 +48,7 @@
|
||||||
"@shopify/lang-jsonc": "1.0.0",
|
"@shopify/lang-jsonc": "1.0.0",
|
||||||
"@tauri-apps/plugin-store": "2.2.0",
|
"@tauri-apps/plugin-store": "2.2.0",
|
||||||
"@types/markdown-it": "14.1.2",
|
"@types/markdown-it": "14.1.2",
|
||||||
|
"@types/hawk": "9.0.6",
|
||||||
"@unhead/vue": "1.11.10",
|
"@unhead/vue": "1.11.10",
|
||||||
"@urql/core": "5.0.6",
|
"@urql/core": "5.0.6",
|
||||||
"@urql/devtools": "2.0.3",
|
"@urql/devtools": "2.0.3",
|
||||||
|
|
@ -66,6 +67,7 @@
|
||||||
"graphql": "16.9.0",
|
"graphql": "16.9.0",
|
||||||
"graphql-language-service-interface": "2.10.2",
|
"graphql-language-service-interface": "2.10.2",
|
||||||
"graphql-tag": "2.12.6",
|
"graphql-tag": "2.12.6",
|
||||||
|
"hawk": "9.0.2",
|
||||||
"insomnia-importers": "3.6.0",
|
"insomnia-importers": "3.6.0",
|
||||||
"io-ts": "2.2.21",
|
"io-ts": "2.2.21",
|
||||||
"js-md5": "0.8.3",
|
"js-md5": "0.8.3",
|
||||||
|
|
|
||||||
|
|
@ -151,6 +151,9 @@
|
||||||
<div v-if="auth.authType === 'aws-signature'">
|
<div v-if="auth.authType === 'aws-signature'">
|
||||||
<HttpAuthorizationAWSSign v-model="auth" :envs="envs" />
|
<HttpAuthorizationAWSSign v-model="auth" :envs="envs" />
|
||||||
</div>
|
</div>
|
||||||
|
<div v-if="auth.authType === 'hawk'">
|
||||||
|
<HttpAuthorizationHAWK v-model="auth" :envs="envs" />
|
||||||
|
</div>
|
||||||
<div v-if="auth.authType === 'digest'">
|
<div v-if="auth.authType === 'digest'">
|
||||||
<HttpAuthorizationDigest v-model="auth" :envs="envs" />
|
<HttpAuthorizationDigest v-model="auth" :envs="envs" />
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -193,6 +196,7 @@ import {
|
||||||
HoppRESTAuth,
|
HoppRESTAuth,
|
||||||
HoppRESTAuthAWSSignature,
|
HoppRESTAuthAWSSignature,
|
||||||
HoppRESTAuthDigest,
|
HoppRESTAuthDigest,
|
||||||
|
HoppRESTAuthHAWK,
|
||||||
HoppRESTAuthOAuth2,
|
HoppRESTAuthOAuth2,
|
||||||
} from "@hoppscotch/data"
|
} from "@hoppscotch/data"
|
||||||
|
|
||||||
|
|
@ -265,6 +269,15 @@ const selectAWSSignatureAuthType = () => {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const selectHAWKAuthType = () => {
|
||||||
|
const { algorithm = "sha256" } = auth.value as HoppRESTAuthHAWK
|
||||||
|
auth.value = {
|
||||||
|
...auth.value,
|
||||||
|
authType: "hawk",
|
||||||
|
algorithm,
|
||||||
|
} as HoppRESTAuth
|
||||||
|
}
|
||||||
|
|
||||||
const selectDigestAuthType = () => {
|
const selectDigestAuthType = () => {
|
||||||
const {
|
const {
|
||||||
username = "",
|
username = "",
|
||||||
|
|
@ -318,6 +331,11 @@ const authTypes: AuthType[] = [
|
||||||
label: "AWS Signature",
|
label: "AWS Signature",
|
||||||
handler: selectAWSSignatureAuthType,
|
handler: selectAWSSignatureAuthType,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
key: "hawk",
|
||||||
|
label: "HAWK",
|
||||||
|
handler: selectHAWKAuthType,
|
||||||
|
},
|
||||||
]
|
]
|
||||||
|
|
||||||
const authType = pluckRef(auth, "authType")
|
const authType = pluckRef(auth, "authType")
|
||||||
|
|
|
||||||
|
|
@ -69,7 +69,7 @@
|
||||||
</div>
|
</div>
|
||||||
<div class="flex flex-1 border-b border-dividerLight">
|
<div class="flex flex-1 border-b border-dividerLight">
|
||||||
<SmartEnvInput
|
<SmartEnvInput
|
||||||
v-model="auth.maxBody"
|
v-model="auth.maxBodySize"
|
||||||
:auto-complete-env="true"
|
:auto-complete-env="true"
|
||||||
placeholder="Max Body Size"
|
placeholder="Max Body Size"
|
||||||
:envs="envs"
|
:envs="envs"
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,9 @@
|
||||||
|
|
||||||
<div class="flex items-center border-b border-dividerLight">
|
<div class="flex items-center border-b border-dividerLight">
|
||||||
<span class="flex items-center">
|
<span class="flex items-center">
|
||||||
<label class="ml-4 text-secondaryLight"> Algorithm </label>
|
<label class="ml-4 text-secondaryLight">
|
||||||
|
{{ t("authorization.digest.algorithm") }}
|
||||||
|
</label>
|
||||||
<tippy
|
<tippy
|
||||||
interactive
|
interactive
|
||||||
trigger="click"
|
trigger="click"
|
||||||
|
|
@ -59,10 +61,15 @@
|
||||||
|
|
||||||
<!-- advanced config -->
|
<!-- advanced config -->
|
||||||
|
|
||||||
<div>
|
<div class="flex flex-col divide-y divide-dividerLight">
|
||||||
<!-- label as advanced config here -->
|
<!-- label as advanced config here -->
|
||||||
<div class="p-4">
|
<div class="p-4 flex flex-col space-y-1">
|
||||||
<label class="text-secondaryLight"> Optional Config </label>
|
<label>
|
||||||
|
{{ t("authorization.advance_config") }}
|
||||||
|
</label>
|
||||||
|
<p class="text-secondaryLight">
|
||||||
|
{{ t("authorization.advance_config_description") }}
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex flex-1 border-b border-dividerLight">
|
<div class="flex flex-1 border-b border-dividerLight">
|
||||||
<SmartEnvInput
|
<SmartEnvInput
|
||||||
|
|
@ -114,14 +121,15 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="px-4 mt-6">
|
<!-- TODO: implement include payload hash -->
|
||||||
|
<!-- <div class="px-4 my-6">
|
||||||
<HoppSmartCheckbox
|
<HoppSmartCheckbox
|
||||||
:on="auth.includePayloadHash"
|
:on="auth.includePayloadHash"
|
||||||
@change="auth.includePayloadHash = !auth.includePayloadHash"
|
@change="auth.includePayloadHash = !auth.includePayloadHash"
|
||||||
>
|
>
|
||||||
Include Payload Hash
|
Include Payload Hash
|
||||||
</HoppSmartCheckbox>
|
</HoppSmartCheckbox>
|
||||||
</div>
|
</div> -->
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
|
|
|
||||||
|
|
@ -35,6 +35,8 @@ import {
|
||||||
fetchInitialDigestAuthInfo,
|
fetchInitialDigestAuthInfo,
|
||||||
generateDigestAuthHeader,
|
generateDigestAuthHeader,
|
||||||
} from "../auth/digest"
|
} from "../auth/digest"
|
||||||
|
import { calculateHawkHeader } from "@hoppscotch/data"
|
||||||
|
|
||||||
export interface EffectiveHoppRESTRequest extends HoppRESTRequest {
|
export interface EffectiveHoppRESTRequest extends HoppRESTRequest {
|
||||||
/**
|
/**
|
||||||
* The effective final URL.
|
* The effective final URL.
|
||||||
|
|
@ -44,7 +46,7 @@ export interface EffectiveHoppRESTRequest extends HoppRESTRequest {
|
||||||
effectiveFinalURL: string
|
effectiveFinalURL: string
|
||||||
effectiveFinalHeaders: HoppRESTHeaders
|
effectiveFinalHeaders: HoppRESTHeaders
|
||||||
effectiveFinalParams: HoppRESTParams
|
effectiveFinalParams: HoppRESTParams
|
||||||
effectiveFinalBody: FormData | string | null | File
|
effectiveFinalBody: FormData | string | null | File | Blob
|
||||||
effectiveFinalRequestVariables: { key: string; value: string }[]
|
effectiveFinalRequestVariables: { key: string; value: string }[]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -245,6 +247,41 @@ export const getComputedAuthHeaders = async (
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
} else if (request.auth.authType === "hawk") {
|
||||||
|
const { method, endpoint } = req as HoppRESTRequest
|
||||||
|
|
||||||
|
const hawkHeader = await calculateHawkHeader({
|
||||||
|
url: parseTemplateString(endpoint, envVars), // URL
|
||||||
|
method: method, // HTTP method
|
||||||
|
id: parseTemplateString(request.auth.authId, envVars),
|
||||||
|
key: parseTemplateString(request.auth.authKey, envVars),
|
||||||
|
algorithm: request.auth.algorithm,
|
||||||
|
|
||||||
|
// advanced parameters (optional)
|
||||||
|
includePayloadHash: request.auth.includePayloadHash,
|
||||||
|
nonce: request.auth.nonce
|
||||||
|
? parseTemplateString(request.auth.nonce, envVars)
|
||||||
|
: undefined,
|
||||||
|
ext: request.auth.ext
|
||||||
|
? parseTemplateString(request.auth.ext, envVars)
|
||||||
|
: undefined,
|
||||||
|
app: request.auth.app
|
||||||
|
? parseTemplateString(request.auth.app, envVars)
|
||||||
|
: undefined,
|
||||||
|
dlg: request.auth.dlg
|
||||||
|
? parseTemplateString(request.auth.dlg, envVars)
|
||||||
|
: undefined,
|
||||||
|
timestamp: request.auth.timestamp
|
||||||
|
? parseInt(parseTemplateString(request.auth.timestamp, envVars), 10)
|
||||||
|
: undefined,
|
||||||
|
})
|
||||||
|
|
||||||
|
headers.push({
|
||||||
|
active: true,
|
||||||
|
key: "Authorization",
|
||||||
|
value: hawkHeader,
|
||||||
|
description: "",
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
return headers
|
return headers
|
||||||
|
|
|
||||||
|
|
@ -76,6 +76,22 @@ export class RequestInspectorService extends Service implements Inspector {
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
matcher: (req) => (req.auth.authType === "hawk" ? {} : null),
|
||||||
|
requires: { type: "auth", name: "hawk" },
|
||||||
|
createInspection: () => ({
|
||||||
|
id: "hawk-auth",
|
||||||
|
icon: markRaw(IconAlertTriangle),
|
||||||
|
text: { type: "text", text: this.t("inspections.auth.hawk") },
|
||||||
|
severity: 2,
|
||||||
|
isApplicable: true,
|
||||||
|
locations: { type: "url" },
|
||||||
|
doc: {
|
||||||
|
text: this.t("action.learn_more"),
|
||||||
|
link: "https://docs.hoppscotch.io/documentation/features/inspections",
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
},
|
||||||
{
|
{
|
||||||
matcher: (req) => {
|
matcher: (req) => {
|
||||||
const index = req.headers.findIndex((h) =>
|
const index = req.headers.findIndex((h) =>
|
||||||
|
|
|
||||||
|
|
@ -25,7 +25,7 @@ const DEFAULT_SETTINGS = getDefaultSettings()
|
||||||
|
|
||||||
export const REST_COLLECTIONS_MOCK: HoppCollection[] = [
|
export const REST_COLLECTIONS_MOCK: HoppCollection[] = [
|
||||||
{
|
{
|
||||||
v: 6,
|
v: 7,
|
||||||
name: "Echo",
|
name: "Echo",
|
||||||
requests: [
|
requests: [
|
||||||
{
|
{
|
||||||
|
|
@ -57,7 +57,7 @@ export const REST_COLLECTIONS_MOCK: HoppCollection[] = [
|
||||||
|
|
||||||
export const GQL_COLLECTIONS_MOCK: HoppCollection[] = [
|
export const GQL_COLLECTIONS_MOCK: HoppCollection[] = [
|
||||||
{
|
{
|
||||||
v: 6,
|
v: 7,
|
||||||
name: "Echo",
|
name: "Echo",
|
||||||
requests: [
|
requests: [
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,7 @@ import V3_VERSION from "./v/3"
|
||||||
import V4_VERSION from "./v/4"
|
import V4_VERSION from "./v/4"
|
||||||
import V5_VERSION from "./v/5"
|
import V5_VERSION from "./v/5"
|
||||||
import V6_VERSION from "./v/6"
|
import V6_VERSION from "./v/6"
|
||||||
|
import V7_VERSION from "./v/7"
|
||||||
|
|
||||||
import { z } from "zod"
|
import { z } from "zod"
|
||||||
import { translateToNewRequest } from "../rest"
|
import { translateToNewRequest } from "../rest"
|
||||||
|
|
@ -17,7 +18,7 @@ const versionedObject = z.object({
|
||||||
})
|
})
|
||||||
|
|
||||||
export const HoppCollection = createVersionedEntity({
|
export const HoppCollection = createVersionedEntity({
|
||||||
latestVersion: 6,
|
latestVersion: 7,
|
||||||
versionMap: {
|
versionMap: {
|
||||||
1: V1_VERSION,
|
1: V1_VERSION,
|
||||||
2: V2_VERSION,
|
2: V2_VERSION,
|
||||||
|
|
@ -25,6 +26,7 @@ export const HoppCollection = createVersionedEntity({
|
||||||
4: V4_VERSION,
|
4: V4_VERSION,
|
||||||
5: V5_VERSION,
|
5: V5_VERSION,
|
||||||
6: V6_VERSION,
|
6: V6_VERSION,
|
||||||
|
7: V7_VERSION,
|
||||||
},
|
},
|
||||||
getVersion(data) {
|
getVersion(data) {
|
||||||
const versionCheck = versionedObject.safeParse(data)
|
const versionCheck = versionedObject.safeParse(data)
|
||||||
|
|
@ -40,7 +42,7 @@ export const HoppCollection = createVersionedEntity({
|
||||||
|
|
||||||
export type HoppCollection = InferredEntity<typeof HoppCollection>
|
export type HoppCollection = InferredEntity<typeof HoppCollection>
|
||||||
|
|
||||||
export const CollectionSchemaVersion = 6
|
export const CollectionSchemaVersion = 7
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generates a Collection object. This ignores the version number object
|
* Generates a Collection object. This ignores the version number object
|
||||||
|
|
|
||||||
37
packages/hoppscotch-data/src/collection/v/7.ts
Normal file
37
packages/hoppscotch-data/src/collection/v/7.ts
Normal file
|
|
@ -0,0 +1,37 @@
|
||||||
|
import { defineVersion } from "verzod"
|
||||||
|
import { z } from "zod"
|
||||||
|
|
||||||
|
import { HoppGQLAuth } from "../../graphql/v/8"
|
||||||
|
import { HoppRESTAuth } from "../../rest/v/12"
|
||||||
|
|
||||||
|
import { V6_SCHEMA, v6_baseCollectionSchema } from "./6"
|
||||||
|
|
||||||
|
export const v7_baseCollectionSchema = v6_baseCollectionSchema.extend({
|
||||||
|
v: z.literal(7),
|
||||||
|
auth: z.union([HoppRESTAuth, HoppGQLAuth]),
|
||||||
|
})
|
||||||
|
|
||||||
|
type Input = z.input<typeof v7_baseCollectionSchema> & {
|
||||||
|
folders: Input[]
|
||||||
|
}
|
||||||
|
|
||||||
|
type Output = z.output<typeof v7_baseCollectionSchema> & {
|
||||||
|
folders: Output[]
|
||||||
|
}
|
||||||
|
|
||||||
|
export const V7_SCHEMA: z.ZodType<Output, z.ZodTypeDef, Input> =
|
||||||
|
v7_baseCollectionSchema.extend({
|
||||||
|
folders: z.lazy(() => z.array(V7_SCHEMA)),
|
||||||
|
})
|
||||||
|
|
||||||
|
export default defineVersion({
|
||||||
|
initial: false,
|
||||||
|
schema: V7_SCHEMA,
|
||||||
|
// @ts-expect-error
|
||||||
|
up(old: z.infer<typeof V6_SCHEMA>) {
|
||||||
|
return {
|
||||||
|
...old,
|
||||||
|
v: 7 as const,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
@ -6,3 +6,5 @@ export * from "./environment"
|
||||||
export * from "./global-environment"
|
export * from "./global-environment"
|
||||||
export * from "./predefinedVariables"
|
export * from "./predefinedVariables"
|
||||||
export * from "./utils/collection"
|
export * from "./utils/collection"
|
||||||
|
export * from "./utils/hawk"
|
||||||
|
export * from "./utils/akamai-eg"
|
||||||
|
|
|
||||||
|
|
@ -18,6 +18,7 @@ import V8_VERSION from "./v/8"
|
||||||
import V9_VERSION from "./v/9"
|
import V9_VERSION from "./v/9"
|
||||||
import V10_VERSION, { HoppRESTReqBody } from "./v/10"
|
import V10_VERSION, { HoppRESTReqBody } from "./v/10"
|
||||||
import V11_VERSION, { HoppRESTAuth, HoppRESTRequestResponses } from "./v/11"
|
import V11_VERSION, { HoppRESTAuth, HoppRESTRequestResponses } from "./v/11"
|
||||||
|
import V12_VERSION from "./v/12"
|
||||||
|
|
||||||
export * from "./content-types"
|
export * from "./content-types"
|
||||||
|
|
||||||
|
|
@ -54,11 +55,13 @@ export {
|
||||||
|
|
||||||
export { HoppRESTReqBody } from "./v/10"
|
export { HoppRESTReqBody } from "./v/10"
|
||||||
|
|
||||||
|
export { HoppRESTAuthOAuth2, ClientCredentialsGrantTypeParams } from "./v/11"
|
||||||
|
|
||||||
export {
|
export {
|
||||||
HoppRESTAuthOAuth2,
|
HoppRESTAuthHAWK,
|
||||||
|
HoppRESTAuthAkamaiEdgeGrid,
|
||||||
HoppRESTAuth,
|
HoppRESTAuth,
|
||||||
ClientCredentialsGrantTypeParams,
|
} from "./v/12"
|
||||||
} from "./v/11"
|
|
||||||
|
|
||||||
const versionedObject = z.object({
|
const versionedObject = z.object({
|
||||||
// v is a stringified number
|
// v is a stringified number
|
||||||
|
|
@ -66,7 +69,7 @@ const versionedObject = z.object({
|
||||||
})
|
})
|
||||||
|
|
||||||
export const HoppRESTRequest = createVersionedEntity({
|
export const HoppRESTRequest = createVersionedEntity({
|
||||||
latestVersion: 11,
|
latestVersion: 12,
|
||||||
versionMap: {
|
versionMap: {
|
||||||
0: V0_VERSION,
|
0: V0_VERSION,
|
||||||
1: V1_VERSION,
|
1: V1_VERSION,
|
||||||
|
|
@ -80,6 +83,7 @@ export const HoppRESTRequest = createVersionedEntity({
|
||||||
9: V9_VERSION,
|
9: V9_VERSION,
|
||||||
10: V10_VERSION,
|
10: V10_VERSION,
|
||||||
11: V11_VERSION,
|
11: V11_VERSION,
|
||||||
|
12: V12_VERSION,
|
||||||
},
|
},
|
||||||
getVersion(data) {
|
getVersion(data) {
|
||||||
// For V1 onwards we have the v string storing the number
|
// For V1 onwards we have the v string storing the number
|
||||||
|
|
@ -122,7 +126,7 @@ const HoppRESTRequestEq = Eq.struct<HoppRESTRequest>({
|
||||||
responses: lodashIsEqualEq,
|
responses: lodashIsEqualEq,
|
||||||
})
|
})
|
||||||
|
|
||||||
export const RESTReqSchemaVersion = "11"
|
export const RESTReqSchemaVersion = "12"
|
||||||
|
|
||||||
export type HoppRESTParam = HoppRESTRequest["params"][number]
|
export type HoppRESTParam = HoppRESTRequest["params"][number]
|
||||||
export type HoppRESTHeader = HoppRESTRequest["headers"][number]
|
export type HoppRESTHeader = HoppRESTRequest["headers"][number]
|
||||||
|
|
|
||||||
85
packages/hoppscotch-data/src/rest/v/12.ts
Normal file
85
packages/hoppscotch-data/src/rest/v/12.ts
Normal file
|
|
@ -0,0 +1,85 @@
|
||||||
|
import {
|
||||||
|
HoppRESTAuthBasic,
|
||||||
|
HoppRESTAuthBearer,
|
||||||
|
HoppRESTAuthInherit,
|
||||||
|
HoppRESTAuthNone,
|
||||||
|
} from "./1"
|
||||||
|
import { HoppRESTAuthAPIKey } from "./4"
|
||||||
|
import { HoppRESTAuthAWSSignature } from "./7"
|
||||||
|
import { HoppRESTAuthDigest } from "./8"
|
||||||
|
|
||||||
|
import { z } from "zod"
|
||||||
|
import { defineVersion } from "verzod"
|
||||||
|
import { HoppRESTAuthOAuth2, V11_SCHEMA } from "./11"
|
||||||
|
|
||||||
|
export const HoppRESTAuthHAWK = z.object({
|
||||||
|
authType: z.literal("hawk"),
|
||||||
|
authId: z.string().catch(""),
|
||||||
|
authKey: z.string().catch(""),
|
||||||
|
algorithm: z.enum(["sha256", "sha1"]).catch("sha256"),
|
||||||
|
includePayloadHash: z.boolean().catch(false),
|
||||||
|
|
||||||
|
// Optional fields
|
||||||
|
user: z.string().optional(),
|
||||||
|
nonce: z.string().optional(),
|
||||||
|
ext: z.string().optional(),
|
||||||
|
app: z.string().optional(),
|
||||||
|
dlg: z.string().optional(),
|
||||||
|
timestamp: z.string().optional(),
|
||||||
|
})
|
||||||
|
|
||||||
|
export const HoppRESTAuthAkamaiEdgeGrid = z.object({
|
||||||
|
authType: z.literal("akamai-eg"),
|
||||||
|
accessToken: z.string().catch(""),
|
||||||
|
clientToken: z.string().catch(""),
|
||||||
|
clientSecret: z.string().catch(""),
|
||||||
|
|
||||||
|
// Optional fields
|
||||||
|
nonce: z.string().optional(),
|
||||||
|
timestamp: z.string().optional(),
|
||||||
|
host: z.string().optional(),
|
||||||
|
headersToSign: z.string().optional(),
|
||||||
|
maxBodySize: z.string().optional(),
|
||||||
|
})
|
||||||
|
|
||||||
|
export type HoppRESTAuthHAWK = z.infer<typeof HoppRESTAuthHAWK>
|
||||||
|
export type HoppRESTAuthAkamaiEdgeGrid = z.infer<
|
||||||
|
typeof HoppRESTAuthAkamaiEdgeGrid
|
||||||
|
>
|
||||||
|
|
||||||
|
export const HoppRESTAuth = z
|
||||||
|
.discriminatedUnion("authType", [
|
||||||
|
HoppRESTAuthNone,
|
||||||
|
HoppRESTAuthInherit,
|
||||||
|
HoppRESTAuthBasic,
|
||||||
|
HoppRESTAuthBearer,
|
||||||
|
HoppRESTAuthOAuth2,
|
||||||
|
HoppRESTAuthAPIKey,
|
||||||
|
HoppRESTAuthAWSSignature,
|
||||||
|
HoppRESTAuthDigest,
|
||||||
|
HoppRESTAuthHAWK,
|
||||||
|
HoppRESTAuthAkamaiEdgeGrid,
|
||||||
|
])
|
||||||
|
.and(
|
||||||
|
z.object({
|
||||||
|
authActive: z.boolean(),
|
||||||
|
})
|
||||||
|
)
|
||||||
|
|
||||||
|
export type HoppRESTAuth = z.infer<typeof HoppRESTAuth>
|
||||||
|
|
||||||
|
export const V12_SCHEMA = V11_SCHEMA.extend({
|
||||||
|
v: z.literal("12"),
|
||||||
|
auth: HoppRESTAuth,
|
||||||
|
})
|
||||||
|
|
||||||
|
export default defineVersion({
|
||||||
|
schema: V12_SCHEMA,
|
||||||
|
initial: false,
|
||||||
|
up(old: z.infer<typeof V11_SCHEMA>) {
|
||||||
|
return {
|
||||||
|
...old,
|
||||||
|
v: "12" as const,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
})
|
||||||
65
packages/hoppscotch-data/src/utils/akamai-eg.ts
Normal file
65
packages/hoppscotch-data/src/utils/akamai-eg.ts
Normal file
|
|
@ -0,0 +1,65 @@
|
||||||
|
export async function calculateAkamaiEdgeGridHeader(params: {
|
||||||
|
accessToken: string
|
||||||
|
clientToken: string
|
||||||
|
clientSecret: string
|
||||||
|
url: string
|
||||||
|
method: string
|
||||||
|
body?: string // Add body parameter
|
||||||
|
nonce?: string
|
||||||
|
timestamp?: string
|
||||||
|
host?: string
|
||||||
|
headersToSign?: string
|
||||||
|
maxBodySize?: string
|
||||||
|
}) {
|
||||||
|
const encoder = new TextEncoder()
|
||||||
|
const decoder = new TextDecoder()
|
||||||
|
|
||||||
|
const timestamp = params.timestamp || Math.floor(Date.now() / 1000).toString()
|
||||||
|
const nonce = params.nonce || crypto.randomUUID()
|
||||||
|
const host = params.host || new URL(params.url).host
|
||||||
|
|
||||||
|
// 1. Create signing key using clientSecret
|
||||||
|
const keyMaterial = await crypto.subtle.importKey(
|
||||||
|
"raw",
|
||||||
|
encoder.encode(params.clientSecret),
|
||||||
|
{ name: "HMAC", hash: "SHA-256" },
|
||||||
|
false,
|
||||||
|
["sign"]
|
||||||
|
)
|
||||||
|
|
||||||
|
const signingKey = await crypto.subtle.sign(
|
||||||
|
"HMAC",
|
||||||
|
keyMaterial,
|
||||||
|
encoder.encode(timestamp)
|
||||||
|
)
|
||||||
|
|
||||||
|
// 2. Calculate content hash if request has body
|
||||||
|
let contentHash = ""
|
||||||
|
if (params.body) {
|
||||||
|
const hashBuffer = await crypto.subtle.digest(
|
||||||
|
"SHA-256",
|
||||||
|
encoder.encode(params.body)
|
||||||
|
)
|
||||||
|
contentHash = Array.from(new Uint8Array(hashBuffer))
|
||||||
|
.map((b) => b.toString(16).padStart(2, "0"))
|
||||||
|
.join("")
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3. Create string to sign
|
||||||
|
const data = `${params.method} ${params.url} ${host} ${timestamp} ${nonce} ${contentHash}`
|
||||||
|
|
||||||
|
// 4. Sign the string using the signing key
|
||||||
|
const signatureBuffer = await crypto.subtle.sign(
|
||||||
|
"HMAC",
|
||||||
|
keyMaterial,
|
||||||
|
encoder.encode(data)
|
||||||
|
)
|
||||||
|
const signature = btoa(
|
||||||
|
String.fromCharCode(...new Uint8Array(signatureBuffer))
|
||||||
|
)
|
||||||
|
|
||||||
|
// 5. Format the final authorization header
|
||||||
|
const authorizationHeader = `EG1-HMAC-SHA256 client_token=${params.clientToken};access_token=${params.accessToken};timestamp=${timestamp};nonce=${nonce};signature=${signature}`
|
||||||
|
|
||||||
|
return authorizationHeader
|
||||||
|
}
|
||||||
146
packages/hoppscotch-data/src/utils/hawk.ts
Normal file
146
packages/hoppscotch-data/src/utils/hawk.ts
Normal file
|
|
@ -0,0 +1,146 @@
|
||||||
|
interface HawkOptions {
|
||||||
|
id: string
|
||||||
|
key: string
|
||||||
|
algorithm: "sha256" | "sha1"
|
||||||
|
method: string
|
||||||
|
url: string
|
||||||
|
includePayloadHash: boolean
|
||||||
|
payload?: string | FormData | File | null
|
||||||
|
|
||||||
|
// Optional parameters
|
||||||
|
user?: string
|
||||||
|
nonce?: string
|
||||||
|
ext?: string
|
||||||
|
app?: string
|
||||||
|
dlg?: string
|
||||||
|
timestamp?: number
|
||||||
|
}
|
||||||
|
|
||||||
|
async function generateNonce(length: number = 6): Promise<string> {
|
||||||
|
const array = new Uint8Array(length)
|
||||||
|
crypto.getRandomValues(array)
|
||||||
|
return Array.from(array)
|
||||||
|
.map((byte) => byte.toString(16).padStart(2, "0"))
|
||||||
|
.join("")
|
||||||
|
.substring(0, length)
|
||||||
|
}
|
||||||
|
|
||||||
|
function sha256Hash(data: string): Promise<ArrayBuffer> {
|
||||||
|
const encoder = new TextEncoder()
|
||||||
|
const dataBuffer = encoder.encode(data)
|
||||||
|
return crypto.subtle.digest("SHA-256", dataBuffer)
|
||||||
|
}
|
||||||
|
|
||||||
|
async function hmacSign(
|
||||||
|
key: string,
|
||||||
|
message: string,
|
||||||
|
algorithm: "sha256" | "sha1"
|
||||||
|
): Promise<string> {
|
||||||
|
const encoder = new TextEncoder()
|
||||||
|
const keyData = encoder.encode(key)
|
||||||
|
const messageData = encoder.encode(message)
|
||||||
|
|
||||||
|
const cryptoAlgo = algorithm === "sha256" ? "SHA-256" : "SHA-1"
|
||||||
|
|
||||||
|
const cryptoKey = await crypto.subtle.importKey(
|
||||||
|
"raw",
|
||||||
|
keyData,
|
||||||
|
{
|
||||||
|
name: "HMAC",
|
||||||
|
hash: { name: cryptoAlgo },
|
||||||
|
},
|
||||||
|
false,
|
||||||
|
["sign"]
|
||||||
|
)
|
||||||
|
|
||||||
|
const signature = await crypto.subtle.sign("HMAC", cryptoKey, messageData)
|
||||||
|
|
||||||
|
// Convert to base64 string
|
||||||
|
return btoa(String.fromCharCode.apply(null, [...new Uint8Array(signature)]))
|
||||||
|
}
|
||||||
|
|
||||||
|
async function getPayloadContent(
|
||||||
|
payload: string | FormData | File | null
|
||||||
|
): Promise<string> {
|
||||||
|
if (!payload) return ""
|
||||||
|
|
||||||
|
if (payload instanceof FormData) {
|
||||||
|
const pairs: string[] = []
|
||||||
|
payload.forEach((value, key) => {
|
||||||
|
pairs.push(`${key}=${value}`)
|
||||||
|
})
|
||||||
|
return pairs.join("&")
|
||||||
|
}
|
||||||
|
|
||||||
|
if (payload instanceof File) {
|
||||||
|
return await payload.text()
|
||||||
|
}
|
||||||
|
|
||||||
|
return payload.toString()
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function calculateHawkHeader(
|
||||||
|
options: HawkOptions
|
||||||
|
): Promise<string> {
|
||||||
|
const timestamp =
|
||||||
|
options.timestamp !== undefined && options.timestamp !== null
|
||||||
|
? options.timestamp
|
||||||
|
: Math.floor(Date.now() / 1000)
|
||||||
|
|
||||||
|
// Use provided nonce or generate a new one
|
||||||
|
const nonce =
|
||||||
|
options.nonce && options.nonce !== ""
|
||||||
|
? options.nonce
|
||||||
|
: await generateNonce()
|
||||||
|
|
||||||
|
// Parse URL
|
||||||
|
const urlObj = new URL(options.url)
|
||||||
|
const host = urlObj.hostname
|
||||||
|
const port = urlObj.port || (urlObj.protocol === "https:" ? "443" : "80")
|
||||||
|
const path = urlObj.pathname + urlObj.search
|
||||||
|
|
||||||
|
// Create the normalized string
|
||||||
|
const artifacts = {
|
||||||
|
ts: timestamp,
|
||||||
|
nonce: nonce,
|
||||||
|
method: options.method.toUpperCase(),
|
||||||
|
resource: path,
|
||||||
|
host: host,
|
||||||
|
port: port,
|
||||||
|
hash: "",
|
||||||
|
ext: options.ext || "",
|
||||||
|
}
|
||||||
|
|
||||||
|
// Calculate payload hash if needed
|
||||||
|
if (options.includePayloadHash && options.payload) {
|
||||||
|
const content = await getPayloadContent(options.payload)
|
||||||
|
const contentType = "text/plain"
|
||||||
|
const hashBase = `hawk.1.payload\n${contentType}\n${content}\n`
|
||||||
|
const contentHash = await sha256Hash(hashBase)
|
||||||
|
artifacts.hash = btoa(
|
||||||
|
String.fromCharCode.apply(null, [...new Uint8Array(contentHash)])
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Construct the string to sign according to Hawk spec
|
||||||
|
const macBaseString = `hawk.1.header\n${artifacts.ts}\n${artifacts.nonce}\n${artifacts.method}\n${artifacts.resource}\n${artifacts.host}\n${artifacts.port}\n${artifacts.hash}\n${artifacts.ext}\n`
|
||||||
|
|
||||||
|
// Calculate MAC
|
||||||
|
const mac = await hmacSign(options.key, macBaseString, options.algorithm)
|
||||||
|
|
||||||
|
// Construct the Hawk header
|
||||||
|
const header = [
|
||||||
|
`Hawk id="${options.id}"`,
|
||||||
|
`ts="${artifacts.ts}"`,
|
||||||
|
`nonce="${artifacts.nonce}"`,
|
||||||
|
`mac="${mac}"`,
|
||||||
|
]
|
||||||
|
|
||||||
|
// Add optional parameters if present
|
||||||
|
if (options.ext && options.ext !== "") header.push(`ext="${options.ext}"`)
|
||||||
|
if (options.app && options.app !== "") header.push(`app="${options.app}"`)
|
||||||
|
if (options.dlg && options.dlg !== "") header.push(`dlg="${options.dlg}"`)
|
||||||
|
if (artifacts.hash !== "") header.push(`hash="${artifacts.hash}"`)
|
||||||
|
|
||||||
|
return header.join(", ")
|
||||||
|
}
|
||||||
|
|
@ -134,7 +134,7 @@ function exportedCollectionToHoppCollection(
|
||||||
|
|
||||||
return {
|
return {
|
||||||
id: restCollection.id,
|
id: restCollection.id,
|
||||||
v: 6,
|
v: 7,
|
||||||
name: restCollection.name,
|
name: restCollection.name,
|
||||||
folders: restCollection.folders.map((folder) =>
|
folders: restCollection.folders.map((folder) =>
|
||||||
exportedCollectionToHoppCollection(folder, collectionType)
|
exportedCollectionToHoppCollection(folder, collectionType)
|
||||||
|
|
@ -196,7 +196,7 @@ function exportedCollectionToHoppCollection(
|
||||||
|
|
||||||
return {
|
return {
|
||||||
id: gqlCollection.id,
|
id: gqlCollection.id,
|
||||||
v: 6,
|
v: 7,
|
||||||
name: gqlCollection.name,
|
name: gqlCollection.name,
|
||||||
folders: gqlCollection.folders.map((folder) =>
|
folders: gqlCollection.folders.map((folder) =>
|
||||||
exportedCollectionToHoppCollection(folder, collectionType)
|
exportedCollectionToHoppCollection(folder, collectionType)
|
||||||
|
|
@ -374,7 +374,7 @@ function setupUserCollectionCreatedSubscription() {
|
||||||
name: res.right.userCollectionCreated.title,
|
name: res.right.userCollectionCreated.title,
|
||||||
folders: [],
|
folders: [],
|
||||||
requests: [],
|
requests: [],
|
||||||
v: 6,
|
v: 7,
|
||||||
auth: data.auth,
|
auth: data.auth,
|
||||||
headers: addDescriptionField(data.headers),
|
headers: addDescriptionField(data.headers),
|
||||||
})
|
})
|
||||||
|
|
@ -382,7 +382,7 @@ function setupUserCollectionCreatedSubscription() {
|
||||||
name: res.right.userCollectionCreated.title,
|
name: res.right.userCollectionCreated.title,
|
||||||
folders: [],
|
folders: [],
|
||||||
requests: [],
|
requests: [],
|
||||||
v: 6,
|
v: 7,
|
||||||
auth: data.auth,
|
auth: data.auth,
|
||||||
headers: addDescriptionField(data.headers),
|
headers: addDescriptionField(data.headers),
|
||||||
})
|
})
|
||||||
|
|
@ -607,7 +607,7 @@ function setupUserCollectionDuplicatedSubscription() {
|
||||||
name,
|
name,
|
||||||
folders,
|
folders,
|
||||||
requests,
|
requests,
|
||||||
v: 6,
|
v: 7,
|
||||||
auth,
|
auth,
|
||||||
headers: addDescriptionField(headers),
|
headers: addDescriptionField(headers),
|
||||||
}
|
}
|
||||||
|
|
@ -1037,7 +1037,7 @@ function transformDuplicatedCollections(
|
||||||
name,
|
name,
|
||||||
folders,
|
folders,
|
||||||
requests,
|
requests,
|
||||||
v: 6,
|
v: 7,
|
||||||
auth,
|
auth,
|
||||||
headers: addDescriptionField(headers),
|
headers: addDescriptionField(headers),
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -140,7 +140,7 @@ function exportedCollectionToHoppCollection(
|
||||||
return {
|
return {
|
||||||
id: restCollection.id,
|
id: restCollection.id,
|
||||||
_ref_id: data._ref_id ?? generateUniqueRefId("coll"),
|
_ref_id: data._ref_id ?? generateUniqueRefId("coll"),
|
||||||
v: 6,
|
v: 7,
|
||||||
name: restCollection.name,
|
name: restCollection.name,
|
||||||
folders: restCollection.folders.map((folder) =>
|
folders: restCollection.folders.map((folder) =>
|
||||||
exportedCollectionToHoppCollection(folder, collectionType)
|
exportedCollectionToHoppCollection(folder, collectionType)
|
||||||
|
|
@ -204,7 +204,7 @@ function exportedCollectionToHoppCollection(
|
||||||
return {
|
return {
|
||||||
id: gqlCollection.id,
|
id: gqlCollection.id,
|
||||||
_ref_id: data._ref_id ?? generateUniqueRefId("coll"),
|
_ref_id: data._ref_id ?? generateUniqueRefId("coll"),
|
||||||
v: 6,
|
v: 7,
|
||||||
name: gqlCollection.name,
|
name: gqlCollection.name,
|
||||||
folders: gqlCollection.folders.map((folder) =>
|
folders: gqlCollection.folders.map((folder) =>
|
||||||
exportedCollectionToHoppCollection(folder, collectionType)
|
exportedCollectionToHoppCollection(folder, collectionType)
|
||||||
|
|
@ -383,7 +383,7 @@ function setupUserCollectionCreatedSubscription() {
|
||||||
name: res.right.userCollectionCreated.title,
|
name: res.right.userCollectionCreated.title,
|
||||||
folders: [],
|
folders: [],
|
||||||
requests: [],
|
requests: [],
|
||||||
v: 6,
|
v: 7,
|
||||||
_ref_id: data._ref_id,
|
_ref_id: data._ref_id,
|
||||||
auth: data.auth,
|
auth: data.auth,
|
||||||
headers: addDescriptionField(data.headers),
|
headers: addDescriptionField(data.headers),
|
||||||
|
|
@ -392,7 +392,7 @@ function setupUserCollectionCreatedSubscription() {
|
||||||
name: res.right.userCollectionCreated.title,
|
name: res.right.userCollectionCreated.title,
|
||||||
folders: [],
|
folders: [],
|
||||||
requests: [],
|
requests: [],
|
||||||
v: 6,
|
v: 7,
|
||||||
_ref_id: data._ref_id,
|
_ref_id: data._ref_id,
|
||||||
auth: data.auth,
|
auth: data.auth,
|
||||||
headers: addDescriptionField(data.headers),
|
headers: addDescriptionField(data.headers),
|
||||||
|
|
@ -620,7 +620,7 @@ function setupUserCollectionDuplicatedSubscription() {
|
||||||
name,
|
name,
|
||||||
folders,
|
folders,
|
||||||
requests,
|
requests,
|
||||||
v: 6,
|
v: 7,
|
||||||
_ref_id,
|
_ref_id,
|
||||||
auth,
|
auth,
|
||||||
headers: addDescriptionField(headers),
|
headers: addDescriptionField(headers),
|
||||||
|
|
@ -1054,7 +1054,7 @@ function transformDuplicatedCollections(
|
||||||
folders,
|
folders,
|
||||||
requests,
|
requests,
|
||||||
_ref_id,
|
_ref_id,
|
||||||
v: 6,
|
v: 7,
|
||||||
auth,
|
auth,
|
||||||
headers: addDescriptionField(headers),
|
headers: addDescriptionField(headers),
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -140,7 +140,7 @@ function exportedCollectionToHoppCollection(
|
||||||
return {
|
return {
|
||||||
id: restCollection.id,
|
id: restCollection.id,
|
||||||
_ref_id: data._ref_id ?? generateUniqueRefId("coll"),
|
_ref_id: data._ref_id ?? generateUniqueRefId("coll"),
|
||||||
v: 6,
|
v: 7,
|
||||||
name: restCollection.name,
|
name: restCollection.name,
|
||||||
folders: restCollection.folders.map((folder) =>
|
folders: restCollection.folders.map((folder) =>
|
||||||
exportedCollectionToHoppCollection(folder, collectionType)
|
exportedCollectionToHoppCollection(folder, collectionType)
|
||||||
|
|
@ -204,7 +204,7 @@ function exportedCollectionToHoppCollection(
|
||||||
return {
|
return {
|
||||||
id: gqlCollection.id,
|
id: gqlCollection.id,
|
||||||
_ref_id: data._ref_id ?? generateUniqueRefId("coll"),
|
_ref_id: data._ref_id ?? generateUniqueRefId("coll"),
|
||||||
v: 6,
|
v: 7,
|
||||||
name: gqlCollection.name,
|
name: gqlCollection.name,
|
||||||
folders: gqlCollection.folders.map((folder) =>
|
folders: gqlCollection.folders.map((folder) =>
|
||||||
exportedCollectionToHoppCollection(folder, collectionType)
|
exportedCollectionToHoppCollection(folder, collectionType)
|
||||||
|
|
@ -383,7 +383,7 @@ function setupUserCollectionCreatedSubscription() {
|
||||||
name: res.right.userCollectionCreated.title,
|
name: res.right.userCollectionCreated.title,
|
||||||
folders: [],
|
folders: [],
|
||||||
requests: [],
|
requests: [],
|
||||||
v: 6,
|
v: 7,
|
||||||
_ref_id: data._ref_id,
|
_ref_id: data._ref_id,
|
||||||
auth: data.auth,
|
auth: data.auth,
|
||||||
headers: addDescriptionField(data.headers),
|
headers: addDescriptionField(data.headers),
|
||||||
|
|
@ -392,7 +392,7 @@ function setupUserCollectionCreatedSubscription() {
|
||||||
name: res.right.userCollectionCreated.title,
|
name: res.right.userCollectionCreated.title,
|
||||||
folders: [],
|
folders: [],
|
||||||
requests: [],
|
requests: [],
|
||||||
v: 6,
|
v: 7,
|
||||||
_ref_id: data._ref_id,
|
_ref_id: data._ref_id,
|
||||||
auth: data.auth,
|
auth: data.auth,
|
||||||
headers: addDescriptionField(data.headers),
|
headers: addDescriptionField(data.headers),
|
||||||
|
|
@ -620,7 +620,7 @@ function setupUserCollectionDuplicatedSubscription() {
|
||||||
name,
|
name,
|
||||||
folders,
|
folders,
|
||||||
requests,
|
requests,
|
||||||
v: 6,
|
v: 7,
|
||||||
_ref_id,
|
_ref_id,
|
||||||
auth,
|
auth,
|
||||||
headers: addDescriptionField(headers),
|
headers: addDescriptionField(headers),
|
||||||
|
|
@ -1054,7 +1054,7 @@ function transformDuplicatedCollections(
|
||||||
folders,
|
folders,
|
||||||
requests,
|
requests,
|
||||||
_ref_id,
|
_ref_id,
|
||||||
v: 6,
|
v: 7,
|
||||||
auth,
|
auth,
|
||||||
headers: addDescriptionField(headers),
|
headers: addDescriptionField(headers),
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -542,6 +542,9 @@ importers:
|
||||||
'@tauri-apps/plugin-store':
|
'@tauri-apps/plugin-store':
|
||||||
specifier: 2.2.0
|
specifier: 2.2.0
|
||||||
version: 2.2.0
|
version: 2.2.0
|
||||||
|
'@types/hawk':
|
||||||
|
specifier: 9.0.6
|
||||||
|
version: 9.0.6
|
||||||
'@types/markdown-it':
|
'@types/markdown-it':
|
||||||
specifier: 14.1.2
|
specifier: 14.1.2
|
||||||
version: 14.1.2
|
version: 14.1.2
|
||||||
|
|
@ -599,6 +602,9 @@ importers:
|
||||||
graphql-tag:
|
graphql-tag:
|
||||||
specifier: 2.12.6
|
specifier: 2.12.6
|
||||||
version: 2.12.6(graphql@16.9.0)
|
version: 2.12.6(graphql@16.9.0)
|
||||||
|
hawk:
|
||||||
|
specifier: 9.0.2
|
||||||
|
version: 9.0.2
|
||||||
insomnia-importers:
|
insomnia-importers:
|
||||||
specifier: 3.6.0
|
specifier: 3.6.0
|
||||||
version: 3.6.0(openapi-types@12.1.3)
|
version: 3.6.0(openapi-types@12.1.3)
|
||||||
|
|
@ -4027,6 +4033,19 @@ packages:
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
graphql: ^0.8.0 || ^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0
|
graphql: ^0.8.0 || ^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0
|
||||||
|
|
||||||
|
'@hapi/b64@5.0.0':
|
||||||
|
resolution: {integrity: sha512-ngu0tSEmrezoiIaNGG6rRvKOUkUuDdf4XTPnONHGYfSGRmDqPZX5oJL6HAdKTo1UQHECbdB4OzhWrfgVppjHUw==}
|
||||||
|
|
||||||
|
'@hapi/boom@9.1.4':
|
||||||
|
resolution: {integrity: sha512-Ls1oH8jaN1vNsqcaHVYJrKmgMcKsC1wcp8bujvXrHaAqD2iDYq3HoOwsxwo09Cuda5R5nC0o0IxlrlTuvPuzSw==}
|
||||||
|
|
||||||
|
'@hapi/cryptiles@5.1.0':
|
||||||
|
resolution: {integrity: sha512-fo9+d1Ba5/FIoMySfMqPBR/7Pa29J2RsiPrl7bkwo5W5o+AN1dAYQRi4SPrPwwVxVGKjgLOEWrsvt1BonJSfLA==}
|
||||||
|
engines: {node: '>=12.0.0'}
|
||||||
|
|
||||||
|
'@hapi/hoek@9.3.0':
|
||||||
|
resolution: {integrity: sha512-/c6rf4UJlmHlC9b5BaNvzAcFv7HZ2QHaV0D4/HNlBdvFnvQq8RI4kYdhyPCl7Xj+oWvTWQ8ujhqS53LIgAe6KQ==}
|
||||||
|
|
||||||
'@hoppscotch/httpsnippet@3.0.7':
|
'@hoppscotch/httpsnippet@3.0.7':
|
||||||
resolution: {integrity: sha512-A7uoYLmkdjekFadnooOjpplFOIr0yHtY/wG63uoTbvL0hoEYH22fDQlJeYIlZe1kdv4q+xjnHj9VgdZQzMbauA==}
|
resolution: {integrity: sha512-A7uoYLmkdjekFadnooOjpplFOIr0yHtY/wG63uoTbvL0hoEYH22fDQlJeYIlZe1kdv4q+xjnHj9VgdZQzMbauA==}
|
||||||
engines: {node: '^14.19.1 || ^16.14.2 || ^18.0.0 '}
|
engines: {node: '^14.19.1 || ^16.14.2 || ^18.0.0 '}
|
||||||
|
|
@ -5275,6 +5294,9 @@ packages:
|
||||||
'@types/body-parser@1.19.5':
|
'@types/body-parser@1.19.5':
|
||||||
resolution: {integrity: sha512-fB3Zu92ucau0iQ0JMCFQE7b/dv8Ot07NI3KaZIkIUNXq82k4eBAqUaneXfleGY9JWskeS9y+u0nXMyspcuQrCg==}
|
resolution: {integrity: sha512-fB3Zu92ucau0iQ0JMCFQE7b/dv8Ot07NI3KaZIkIUNXq82k4eBAqUaneXfleGY9JWskeS9y+u0nXMyspcuQrCg==}
|
||||||
|
|
||||||
|
'@types/caseless@0.12.5':
|
||||||
|
resolution: {integrity: sha512-hWtVTC2q7hc7xZ/RLbxapMvDMgUnDvKvMOpKal4DrMyfGBUfB1oKaZlIRr6mJL+If3bAP6sV/QneGzF6tJjZDg==}
|
||||||
|
|
||||||
'@types/connect@3.4.38':
|
'@types/connect@3.4.38':
|
||||||
resolution: {integrity: sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==}
|
resolution: {integrity: sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==}
|
||||||
|
|
||||||
|
|
@ -5293,6 +5315,9 @@ packages:
|
||||||
'@types/cors@2.8.17':
|
'@types/cors@2.8.17':
|
||||||
resolution: {integrity: sha512-8CGDvrBj1zgo2qE+oS3pOCyYNqCPryMWY2bGfwA0dcfopWGgxs+78df0Rs3rc9THP4JkOhLsAa+15VdpAqkcUA==}
|
resolution: {integrity: sha512-8CGDvrBj1zgo2qE+oS3pOCyYNqCPryMWY2bGfwA0dcfopWGgxs+78df0Rs3rc9THP4JkOhLsAa+15VdpAqkcUA==}
|
||||||
|
|
||||||
|
'@types/crypto-js@4.2.2':
|
||||||
|
resolution: {integrity: sha512-sDOLlVbHhXpAUAL0YHDUUwDZf3iN4Bwi4W6a0W0b+QcAezUbRtH4FVb+9J4h+XFPW7l/gQ9F8qC7P+Ec4k8QVQ==}
|
||||||
|
|
||||||
'@types/debug@4.1.12':
|
'@types/debug@4.1.12':
|
||||||
resolution: {integrity: sha512-vIChWdVG3LG1SMxEvI/AK+FWJthlrqlTu7fbrlywTkkaONwk/UAGaULXRlf8vkzFBLVm0zkMdCquhL5aOjhXPQ==}
|
resolution: {integrity: sha512-vIChWdVG3LG1SMxEvI/AK+FWJthlrqlTu7fbrlywTkkaONwk/UAGaULXRlf8vkzFBLVm0zkMdCquhL5aOjhXPQ==}
|
||||||
|
|
||||||
|
|
@ -5326,6 +5351,9 @@ packages:
|
||||||
'@types/har-format@1.2.16':
|
'@types/har-format@1.2.16':
|
||||||
resolution: {integrity: sha512-fluxdy7ryD3MV6h8pTfTYpy/xQzCFC7m89nOH9y94cNqJ1mDIDPut7MnRHI3F6qRmh/cT2fUjG1MLdCNb4hE9A==}
|
resolution: {integrity: sha512-fluxdy7ryD3MV6h8pTfTYpy/xQzCFC7m89nOH9y94cNqJ1mDIDPut7MnRHI3F6qRmh/cT2fUjG1MLdCNb4hE9A==}
|
||||||
|
|
||||||
|
'@types/hawk@9.0.6':
|
||||||
|
resolution: {integrity: sha512-yowsKIXd1wlNsn7cc4o2uWDTGJYj236R0uvN34aWmB5R4SSOj3/V3nHYBm9DfkhFvteyYuy45jZQnNai31DtaQ==}
|
||||||
|
|
||||||
'@types/http-errors@2.0.4':
|
'@types/http-errors@2.0.4':
|
||||||
resolution: {integrity: sha512-D0CFMMtydbJAegzOyHjtiKPLlvnm3iTZyZRSZoLq2mRhDdmLfIWOCYPfQJ4cu2erKghU++QvjcUjp/5h7hESpA==}
|
resolution: {integrity: sha512-D0CFMMtydbJAegzOyHjtiKPLlvnm3iTZyZRSZoLq2mRhDdmLfIWOCYPfQJ4cu2erKghU++QvjcUjp/5h7hESpA==}
|
||||||
|
|
||||||
|
|
@ -5467,6 +5495,9 @@ packages:
|
||||||
'@types/range-parser@1.2.7':
|
'@types/range-parser@1.2.7':
|
||||||
resolution: {integrity: sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==}
|
resolution: {integrity: sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==}
|
||||||
|
|
||||||
|
'@types/request@2.48.12':
|
||||||
|
resolution: {integrity: sha512-G3sY+NpsA9jnwm0ixhAFQSJ3Q9JkpLZpJbI3GMv0mIAT0y3mRabYeINzal5WOChIiaTEGQYlHOKgkaM9EisWHw==}
|
||||||
|
|
||||||
'@types/resolve@1.20.2':
|
'@types/resolve@1.20.2':
|
||||||
resolution: {integrity: sha512-60BCwRFOZCQhDncwQdxxeOEEkbc5dIMccYLwbxsS4TUNeVECQ/pBJ0j09mrHOl/JJvpRPGwO9SvE4nR2Nb/a4Q==}
|
resolution: {integrity: sha512-60BCwRFOZCQhDncwQdxxeOEEkbc5dIMccYLwbxsS4TUNeVECQ/pBJ0j09mrHOl/JJvpRPGwO9SvE4nR2Nb/a4Q==}
|
||||||
|
|
||||||
|
|
@ -5500,6 +5531,9 @@ packages:
|
||||||
'@types/supertest@6.0.2':
|
'@types/supertest@6.0.2':
|
||||||
resolution: {integrity: sha512-137ypx2lk/wTQbW6An6safu9hXmajAifU/s7szAHLN/FeIm5w7yR0Wkl9fdJMRSHwOn4HLAI0DaB2TOORuhPDg==}
|
resolution: {integrity: sha512-137ypx2lk/wTQbW6An6safu9hXmajAifU/s7szAHLN/FeIm5w7yR0Wkl9fdJMRSHwOn4HLAI0DaB2TOORuhPDg==}
|
||||||
|
|
||||||
|
'@types/tough-cookie@4.0.5':
|
||||||
|
resolution: {integrity: sha512-/Ad8+nIOV7Rl++6f1BdKxFSMgmoqEoYbHRpPcx3JEfv8VRsQe9Z4mCXeJBzxs7mbHY/XOZZuXlRNfhpVPbs6ZA==}
|
||||||
|
|
||||||
'@types/trusted-types@2.0.7':
|
'@types/trusted-types@2.0.7':
|
||||||
resolution: {integrity: sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==}
|
resolution: {integrity: sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==}
|
||||||
|
|
||||||
|
|
@ -8120,6 +8154,10 @@ packages:
|
||||||
typescript: '>3.6.0'
|
typescript: '>3.6.0'
|
||||||
webpack: ^5.11.0
|
webpack: ^5.11.0
|
||||||
|
|
||||||
|
form-data@2.5.2:
|
||||||
|
resolution: {integrity: sha512-GgwY0PS7DbXqajuGf4OYlsrIu3zgxD6Vvql43IBhm6MahqA5SK/7mwhtNj2AdH2z35YR34ujJ7BN+3fFC3jP5Q==}
|
||||||
|
engines: {node: '>= 0.12'}
|
||||||
|
|
||||||
form-data@4.0.0:
|
form-data@4.0.0:
|
||||||
resolution: {integrity: sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==}
|
resolution: {integrity: sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==}
|
||||||
engines: {node: '>= 6'}
|
engines: {node: '>= 6'}
|
||||||
|
|
@ -8455,6 +8493,9 @@ packages:
|
||||||
resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==}
|
resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==}
|
||||||
engines: {node: '>= 0.4'}
|
engines: {node: '>= 0.4'}
|
||||||
|
|
||||||
|
hawk@9.0.2:
|
||||||
|
resolution: {integrity: sha512-EJMLBZAWg+EoI/aAJWDhrYGvucWYvY37CdGXolkol0ITGswkDHtDnjbFcPBaIv3jbtpfWqYjXMm4KhfXPOLCRg==}
|
||||||
|
|
||||||
he@1.2.0:
|
he@1.2.0:
|
||||||
resolution: {integrity: sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==}
|
resolution: {integrity: sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==}
|
||||||
hasBin: true
|
hasBin: true
|
||||||
|
|
@ -10845,7 +10886,6 @@ packages:
|
||||||
engines: {node: '>=0.6.0', teleport: '>=0.2.0'}
|
engines: {node: '>=0.6.0', teleport: '>=0.2.0'}
|
||||||
deprecated: |-
|
deprecated: |-
|
||||||
You or someone you depend on is using Q, the JavaScript Promise library that gave JavaScript developers strong feelings about promises. They can almost certainly migrate to the native JavaScript promise now. Thank you literally everyone for joining me in this bet against the odds. Be excellent to each other.
|
You or someone you depend on is using Q, the JavaScript Promise library that gave JavaScript developers strong feelings about promises. They can almost certainly migrate to the native JavaScript promise now. Thank you literally everyone for joining me in this bet against the odds. Be excellent to each other.
|
||||||
|
|
||||||
(For a CapTP with native promises, see @endo/eventual-send and @endo/captp)
|
(For a CapTP with native promises, see @endo/eventual-send and @endo/captp)
|
||||||
|
|
||||||
qs@6.11.0:
|
qs@6.11.0:
|
||||||
|
|
@ -15965,6 +16005,20 @@ snapshots:
|
||||||
dependencies:
|
dependencies:
|
||||||
graphql: 16.9.0
|
graphql: 16.9.0
|
||||||
|
|
||||||
|
'@hapi/b64@5.0.0':
|
||||||
|
dependencies:
|
||||||
|
'@hapi/hoek': 9.3.0
|
||||||
|
|
||||||
|
'@hapi/boom@9.1.4':
|
||||||
|
dependencies:
|
||||||
|
'@hapi/hoek': 9.3.0
|
||||||
|
|
||||||
|
'@hapi/cryptiles@5.1.0':
|
||||||
|
dependencies:
|
||||||
|
'@hapi/boom': 9.1.4
|
||||||
|
|
||||||
|
'@hapi/hoek@9.3.0': {}
|
||||||
|
|
||||||
'@hoppscotch/httpsnippet@3.0.7':
|
'@hoppscotch/httpsnippet@3.0.7':
|
||||||
dependencies:
|
dependencies:
|
||||||
ajv: 6.12.3
|
ajv: 6.12.3
|
||||||
|
|
@ -17515,6 +17569,8 @@ snapshots:
|
||||||
'@types/connect': 3.4.38
|
'@types/connect': 3.4.38
|
||||||
'@types/node': 22.9.3
|
'@types/node': 22.9.3
|
||||||
|
|
||||||
|
'@types/caseless@0.12.5': {}
|
||||||
|
|
||||||
'@types/connect@3.4.38':
|
'@types/connect@3.4.38':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@types/node': 22.9.3
|
'@types/node': 22.9.3
|
||||||
|
|
@ -17535,6 +17591,8 @@ snapshots:
|
||||||
dependencies:
|
dependencies:
|
||||||
'@types/node': 22.9.3
|
'@types/node': 22.9.3
|
||||||
|
|
||||||
|
'@types/crypto-js@4.2.2': {}
|
||||||
|
|
||||||
'@types/debug@4.1.12':
|
'@types/debug@4.1.12':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@types/ms': 0.7.34
|
'@types/ms': 0.7.34
|
||||||
|
|
@ -17585,6 +17643,13 @@ snapshots:
|
||||||
|
|
||||||
'@types/har-format@1.2.16': {}
|
'@types/har-format@1.2.16': {}
|
||||||
|
|
||||||
|
'@types/hawk@9.0.6':
|
||||||
|
dependencies:
|
||||||
|
'@hapi/boom': 9.1.4
|
||||||
|
'@types/crypto-js': 4.2.2
|
||||||
|
'@types/node': 22.7.6
|
||||||
|
'@types/request': 2.48.12
|
||||||
|
|
||||||
'@types/http-errors@2.0.4': {}
|
'@types/http-errors@2.0.4': {}
|
||||||
|
|
||||||
'@types/istanbul-lib-coverage@2.0.6': {}
|
'@types/istanbul-lib-coverage@2.0.6': {}
|
||||||
|
|
@ -17745,6 +17810,13 @@ snapshots:
|
||||||
|
|
||||||
'@types/range-parser@1.2.7': {}
|
'@types/range-parser@1.2.7': {}
|
||||||
|
|
||||||
|
'@types/request@2.48.12':
|
||||||
|
dependencies:
|
||||||
|
'@types/caseless': 0.12.5
|
||||||
|
'@types/node': 22.7.6
|
||||||
|
'@types/tough-cookie': 4.0.5
|
||||||
|
form-data: 2.5.2
|
||||||
|
|
||||||
'@types/resolve@1.20.2': {}
|
'@types/resolve@1.20.2': {}
|
||||||
|
|
||||||
'@types/sax@1.2.7':
|
'@types/sax@1.2.7':
|
||||||
|
|
@ -17787,6 +17859,8 @@ snapshots:
|
||||||
'@types/methods': 1.1.4
|
'@types/methods': 1.1.4
|
||||||
'@types/superagent': 8.1.7
|
'@types/superagent': 8.1.7
|
||||||
|
|
||||||
|
'@types/tough-cookie@4.0.5': {}
|
||||||
|
|
||||||
'@types/trusted-types@2.0.7': {}
|
'@types/trusted-types@2.0.7': {}
|
||||||
|
|
||||||
'@types/uuid@10.0.0': {}
|
'@types/uuid@10.0.0': {}
|
||||||
|
|
@ -21532,6 +21606,13 @@ snapshots:
|
||||||
typescript: 5.3.3
|
typescript: 5.3.3
|
||||||
webpack: 5.94.0(@swc/core@1.4.2)
|
webpack: 5.94.0(@swc/core@1.4.2)
|
||||||
|
|
||||||
|
form-data@2.5.2:
|
||||||
|
dependencies:
|
||||||
|
asynckit: 0.4.0
|
||||||
|
combined-stream: 1.0.8
|
||||||
|
mime-types: 2.1.35
|
||||||
|
safe-buffer: 5.2.1
|
||||||
|
|
||||||
form-data@4.0.0:
|
form-data@4.0.0:
|
||||||
dependencies:
|
dependencies:
|
||||||
asynckit: 0.4.0
|
asynckit: 0.4.0
|
||||||
|
|
@ -21969,6 +22050,13 @@ snapshots:
|
||||||
dependencies:
|
dependencies:
|
||||||
function-bind: 1.1.2
|
function-bind: 1.1.2
|
||||||
|
|
||||||
|
hawk@9.0.2:
|
||||||
|
dependencies:
|
||||||
|
'@hapi/b64': 5.0.0
|
||||||
|
'@hapi/boom': 9.1.4
|
||||||
|
'@hapi/cryptiles': 5.1.0
|
||||||
|
'@hapi/hoek': 9.3.0
|
||||||
|
|
||||||
he@1.2.0: {}
|
he@1.2.0: {}
|
||||||
|
|
||||||
header-case@2.0.4:
|
header-case@2.0.4:
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue