Skip to content

Commit

Permalink
fix: allow referrer header in request options
Browse files Browse the repository at this point in the history
  • Loading branch information
ahsan-javaid authored and janniks committed May 9, 2022
1 parent 49a094b commit 70ea915
Show file tree
Hide file tree
Showing 9 changed files with 94 additions and 36 deletions.
36 changes: 31 additions & 5 deletions packages/common/src/fetchUtil.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,38 @@
import 'cross-fetch/polyfill';

// Define a default request options and allow modification using getters, setters
// Reference: https://developer.mozilla.org/en-US/docs/Web/API/Request/Request
const defaultFetchOpts: RequestInit = {
// By default referrer value will be client:origin: above reference link
referrerPolicy: 'origin', // Use origin value for referrer policy
// https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Referrer-Policy
};
/*
* Get fetch options
* @return fetchOptions
*/
export const getFetchOptions = () => {
return defaultFetchOpts;
};
/*
* Set fetch options
* Users can change default referrer as well as other options when fetch is used internally by stacks.js libraries or from server side
* @example
* Reference: https://developer.mozilla.org/en-US/docs/Web/API/Request/Request
* setFetchOptions({ referrer: 'no-referrer', referrerPolicy: 'no-referrer', ... other options as per above reference });
* Now all the subsequent fetchPrivate will use above options
* @return fetchOptions
*/
export const setFetchOptions = (ops: RequestInit) => {
return Object.assign(defaultFetchOpts, ops);
};

/** @ignore */
export async function fetchPrivate(input: RequestInfo, init?: RequestInit): Promise<Response> {
const defaultFetchOpts: RequestInit = {
referrer: 'no-referrer',
referrerPolicy: 'no-referrer',
};
const fetchOpts = Object.assign(defaultFetchOpts, init);
const fetchOpts = {};
// Use the provided options in request options along with default or user provided values
Object.assign(fetchOpts, init, defaultFetchOpts);

const fetchResult = await fetch(input, fetchOpts);
return fetchResult;
}
28 changes: 28 additions & 0 deletions packages/common/tests/fetch.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import { fetchPrivate, getFetchOptions, setFetchOptions } from '../src'
import fetchMock from "jest-fetch-mock";

test('Verify fetch private options', async () => {
const defaultOptioins = getFetchOptions();

expect(defaultOptioins).toEqual({ referrerPolicy: 'origin' });

// Override default options when fetchPrivate is called internally by other stacks.js libraries like transactions or from server side
// This is for developers as they cannot directly pass options directly in fetchPrivate
const modifiedOptions: RequestInit= { referrer: 'http://test.com', referrerPolicy: 'same-origin' };

// Developers can set fetch options globally one time specifically when fetchPrivate is used internally by stacks.js libraries
setFetchOptions(modifiedOptions);

expect(getFetchOptions()).toEqual(modifiedOptions);

// Browser will replace about:client with actual url but it will not be visible in test case
fetchMock.mockOnce(`{ status: 'success'}`, { headers: modifiedOptions as any });

const result = await fetchPrivate('https://example.com');

// Verify the request options
expect(result.status).toEqual(200);
expect(result.headers.get('referrer')).toEqual(modifiedOptions.referrer);
expect(result.headers.get('referrerPolicy')).toEqual(modifiedOptions.referrerPolicy);
})

3 changes: 2 additions & 1 deletion packages/keychain/src/identity.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { Identity as IdentifyInterface, Profile } from './common';
import IdentityAddressOwnerNode from './nodes/identity-address-owner-node';
import { DEFAULT_PROFILE, fetchProfile, signAndUploadProfile } from './profiles';
import { getProfileURLFromZoneFile, IdentityKeyPair } from './utils';
import { fetchPrivate } from '@stacks/common';
import {
connectToGaiaHubWithConfig,
DEFAULT_GAIA_HUB,
Expand Down Expand Up @@ -131,7 +132,7 @@ export class Identity implements IdentifyInterface {

async fetchNames() {
const getNamesUrl = `https://stacks-node-api.stacks.co/v1/addresses/bitcoin/${this.address}`;
const res = await fetch(getNamesUrl);
const res = await fetchPrivate(getNamesUrl);
const data = await res.json();
const { names }: { names: string[] } = data;
return names;
Expand Down
5 changes: 3 additions & 2 deletions packages/keychain/src/profiles.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { Identity, Profile } from './common';
import { IdentityKeyPair } from './utils';
import { uploadToGaiaHub } from './utils/gaia';
import { GaiaHubConfig } from '@stacks/storage';
import { fetchPrivate } from '@stacks/common';

export const DEFAULT_PROFILE: Profile = {
'@type': 'Person',
Expand Down Expand Up @@ -81,7 +82,7 @@ const sendUsernameToRegistrar = async ({
'Content-Type': 'application/json',
};

const response = await fetch(registerUrl, {
const response = await fetchPrivate(registerUrl, {
method: 'POST',
headers: requestHeaders,
body: registrationRequestBody,
Expand Down Expand Up @@ -156,7 +157,7 @@ export const fetchProfile = async ({
}) => {
try {
const url = await identity.profileUrl(gaiaUrl);
const res = await fetch(url);
const res = await fetchPrivate(url);
if (res.ok) {
const json = await res.json();
const { decodedToken } = json[0];
Expand Down
27 changes: 15 additions & 12 deletions packages/keychain/src/utils/gaia.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// @ts-ignore
import { Buffer } from '@stacks/common';
import { Buffer, fetchPrivate } from '@stacks/common';
import { TokenSigner, Json } from 'jsontokens';
import { getPublicKeyFromPrivate, publicKeyToAddress } from '@stacks/encryption';
import randomBytes from 'randombytes';
Expand All @@ -13,7 +13,7 @@ interface HubInfo {
}

export const getHubInfo = async (hubUrl: string) => {
const response = await fetch(`${hubUrl}/hub_info`);
const response = await fetchPrivate(`${hubUrl}/hub_info`);
const data: HubInfo = await response.json();
return data;
};
Expand Down Expand Up @@ -115,16 +115,19 @@ export const uploadToGaiaHub = async (
): Promise<string> => {
const contentType = 'application/json';

const response = await fetch(`${hubConfig.server}/store/${hubConfig.address}/${filename}`, {
method: 'POST',
headers: {
'Content-Type': contentType,
Authorization: `bearer ${hubConfig.token}`,
},
body: contents,
referrer: 'no-referrer',
referrerPolicy: 'no-referrer',
});
const response = await fetchPrivate(
`${hubConfig.server}/store/${hubConfig.address}/${filename}`,
{
method: 'POST',
headers: {
'Content-Type': contentType,
Authorization: `bearer ${hubConfig.token}`,
},
body: contents,
referrer: 'no-referrer',
referrerPolicy: 'no-referrer',
}
);
const { publicURL } = await response.json();
return publicURL;
};
6 changes: 3 additions & 3 deletions packages/keychain/src/utils/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Buffer } from '@stacks/common';
import { Buffer, fetchPrivate } from '@stacks/common';
import { BIP32Interface } from 'bitcoinjs-lib';
import IdentityAddressOwnerNode from '../nodes/identity-address-owner-node';
import { createSha2Hash, publicKeyToAddress } from '@stacks/encryption';
Expand Down Expand Up @@ -185,7 +185,7 @@ export const validateSubdomainAvailability = async (
subdomain: Subdomains = Subdomains.BLOCKSTACK
) => {
const url = `${registrars[subdomain].apiUrl}/${name.toLowerCase()}.${subdomain}`;
const resp = await fetch(url);
const resp = await fetchPrivate(url);
const data = await resp.json();
return data;
};
Expand Down Expand Up @@ -249,7 +249,7 @@ interface NameInfoResponse {

export const getProfileURLFromZoneFile = async (name: string) => {
const url = `https://stacks-node-api.stacks.co/v1/names/${name}`;
const res = await fetch(url);
const res = await fetchPrivate(url);
if (res.ok) {
const nameInfo: NameInfoResponse = await res.json();
const zone = parseZoneFile(nameInfo.zonefile);
Expand Down
4 changes: 2 additions & 2 deletions packages/keychain/src/wallet/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Buffer } from '@stacks/common';
import { Buffer, fetchPrivate } from '@stacks/common';
import { mnemonicToSeed } from 'bip39';
import { bip32, BIP32Interface } from 'bitcoinjs-lib';
import { ChainID } from '@stacks/transactions';
Expand Down Expand Up @@ -227,7 +227,7 @@ export class Wallet {

async fetchConfig(gaiaConfig: GaiaHubConfig): Promise<WalletConfig | null> {
try {
const response = await fetch(
const response = await fetchPrivate(
`${gaiaConfig.url_prefix}${gaiaConfig.address}/wallet-config.json`
);
const encrypted = await response.text();
Expand Down
14 changes: 3 additions & 11 deletions packages/transactions/src/utils.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
import { Buffer } from '@stacks/common';
import { Buffer, fetchPrivate } from '@stacks/common';
import { sha256, sha512 } from 'sha.js';
import { ClarityValue, serializeCV } from './clarity';
import RIPEMD160 from 'ripemd160-min';
import { utils } from '@noble/secp256k1';
import { deserializeCV } from './clarity';
import fetch from 'cross-fetch';
import { c32addressDecode } from 'c32check';
import lodashCloneDeep from 'lodash.clonedeep';
import { with0x } from '@stacks/common';
Expand Down Expand Up @@ -199,15 +198,8 @@ export function isClarityName(name: string) {
}

/** @ignore */
export async function fetchPrivate(input: RequestInfo, init?: RequestInit): Promise<Response> {
const defaultFetchOpts: RequestInit = {
referrer: 'no-referrer',
referrerPolicy: 'no-referrer',
};
const fetchOpts = Object.assign(defaultFetchOpts, init);
const fetchResult = await fetch(input, fetchOpts);
return fetchResult;
}
export { fetchPrivate };

/**
* Converts a clarity value to a hex encoded string with `0x` prefix
* @param {ClarityValue} cv - the clarity value to convert
Expand Down
7 changes: 7 additions & 0 deletions packages/wallet-sdk/tests/models/wallet.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,13 @@ test('restore wallet with username owned by stx private key', async () => {
fetchMock
.once(mockGaiaHubInfo)
.once(JSON.stringify('no found'), { status: 404 }) // TODO mock fetch legacy wallet config
.once(JSON.stringify({ // mock wallet-config.json
iv: "a39461ec18e5dea8ac759d5b8141319d",
ephemeralPK: "03e04d0046a9dd5b7a8fea4de55a8d912909738b26f2c72f8e5962217fa45f00bb",
cipherText: "bf16d2da29b54a153d553ab99597096f3fa11bd964441927355c1d979bf614477c8ceba7098620a37fa98f92f0f79813f771b6e2c2087e6fd2b1675d98a5e14f28cba28134dac2913bcb06f469439a16b47778747c7e93f50169727a7b9053b5441c8645fc729b28f063d2ffd673a01342e2cbc4fbf0e05350a67ec53ee3b7e43ff4e2dddbded5868cc3f5c4ca323b621bd13b5f9f036dc4406c2418e98b1b905974479cc79ab102d9ba1eb7fe858987dd0777ed3b0356d6bd0bc775213ef878bffaa58c40365d831a9e436fbfc388bcff2909659cab38a65ae8512508f6fda247437d4819c98ea15e48a4a00c1594eb58f7bf7eb85aad7cd51e5b43a7ca1fec06385be125d0b8c07bac1ac1094bb4687e620f23a5a14f4b20674ccd198271eb2451f12ad294efa79a9b5a001a3682a5ec833140b78333f57ce9912f60ff94edf99ee0b5e59ddfe7fb4a1472c0d303eeab22471585a5a5689ed9779e4ded10a4feecf5107df4c847522b2d6c95ed1e45cccb8b834b47a79f6671b49ffbdb02e4887465ca521472b7f11a53be0221eaeeffed2c6cf4d17a6fdae4b8f2b963d8a102c5376e6fa01bdaf9dc3d544c9954090b23fc02c8f500319b0cc43d7f73ff5012514d473afc818967eb0d0837a9c6920f9bc39e5f49fefdbc4fa33e6be88820a1abaeacb836bd398e7031d4286121383f53e2873ea1c2f0b649a12aec7db049505c58323fb34aaaf8d59fc0b962df05b8e9ea0dabf7fc9923b25af9ff3bd08a0b2dea7462a9e889485aba8605592308847468e843fca721a70aae9528d4abaae1a539f57c624f06b5b7dfdcf0a9d94b509697a1d0020b5f0b60ab19cc6abaf14928612663a9b6f15e18174a0a31fc506c428df13889fd877b7b639106d72c1b9dc8509758035337776c9d2d489da61f8de92a880b8ab802bd098fea111ab6af59fadd275285c59a98f824d5023990664856f971a6928869d3447f4426cb6855be55e43778f65a77e4d4348da0eda3e45e56a5d8fd11aff6ec62f53eac1cd862",
mac: "623331e6804bf8c0dee7db7894a84ed02c70bf1ec0b6a5b2ccaff7d0638a9d88",
wasString: true
}))
.once(JSON.stringify({ names: ['public_profile_for_testing.id.blockstack'] }))
.once(JSON.stringify('ok')); // updateWalletConfig

Expand Down

1 comment on commit 70ea915

@vercel
Copy link

@vercel vercel bot commented on 70ea915 May 9, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.