js-sha256#sha256 TypeScript Examples

The following examples show how to use js-sha256#sha256. You can vote up the ones you like or vote down the ones you don't like, and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example #1
Source File: utils.ts    From helium-js with Apache License 2.0 7 votes vote down vote up
bs58CheckEncode = (version: number, binary: Buffer | Uint8Array): string => {
  const vPayload = Buffer.concat([
    Buffer.from([version]),
    binary,
  ])

  const checksum = sha256(Buffer.from(sha256(vPayload), 'hex'))
  const checksumBytes = Buffer.alloc(4, checksum, 'hex')

  const result = Buffer.concat([
    vPayload,
    checksumBytes,
  ])

  return bs58.encode(result)
}
Example #2
Source File: utils.ts    From helium-js with Apache License 2.0 7 votes vote down vote up
bs58ToBin = (bs58Address: string): Buffer => {
  const bin = bs58.decode(bs58Address)
  const vPayload = bin.slice(0, -4)
  const payload = bin.slice(1, -4)
  const checksum = bin.slice(-4)

  const checksumVerify = sha256(Buffer.from(sha256(vPayload), 'hex'))
  const checksumVerifyBytes = Buffer.alloc(4, checksumVerify, 'hex')

  if (!checksumVerifyBytes.equals(Buffer.from(checksum))) {
    throw new Error('invalid checksum')
  }

  return Buffer.from(payload)
}
Example #3
Source File: common.ts    From algo-builder with Apache License 2.0 6 votes vote down vote up
/**
 * Prepares parameters for htlc run and deploy tasks
 *  - alice account
 *  - bob account
 *  - secret value
 *  - hash of secret
 *  - pyteal template params (to pass to htlc.py)
 * @param deployer Deployer
 */
export function prepareParameters(deployer: algob.types.Deployer): any {
	const bob = getDeployerAccount(deployer, "bob");
	const alice = getDeployerAccount(deployer, "alice");

	const secret = "hero wisdom green split loop element vote belt";
	const secretHash = Buffer.from(sha256.digest(secret)).toString("base64");

	const scTmplParams = { bob: bob.addr, alice: alice.addr, hash_image: secretHash };
	return { alice, bob, secret, scTmplParams, secretHash };
}
Example #4
Source File: session.ts    From F95API with MIT License 6 votes vote down vote up
//#endregion Private Methods

  //#region Public Methods

  /**
   * Create a new session.
   */
  create(username: string, password: string, token: string): void {
    // First, create the _hash of the credentials
    const value = `${username}%%%${password}`;
    this._hash = sha256(value);

    // Set the token
    this._token = token;

    // Update the creation date
    this._created = new Date(Date.now());
  }
Example #5
Source File: session.ts    From F95API with MIT License 6 votes vote down vote up
/**
   * Check if the session is valid.
   */
  isValid(username: string, password: string): boolean {
    // Local variables
    const now = new Date(Date.now());

    // Get the number of days from the file creation
    const sessionDateDiff = this.dateDiffInDays(now, this.created);

    // The session is valid if the number of days is minor than SESSION_TIME
    const sessionDateValid = sessionDateDiff < this.SESSION_TIME;

    // Check the hash
    const value = `${username}%%%${password}`;
    const hashValid = sha256(value) === this._hash;

    // Verify if the user cookie is valid
    const xfUser = this._cookieJar.getCookiesSync(urls.BASE).find((c) => c.key === "xf_user");
    const cookieCreation = xfUser ? xfUser.creation : DEFAULT_DATE;
    const cookieDateDiff = this.dateDiffInDays(now, cookieCreation);

    // The cookie has a validity of one year, however it is limited to SESSION_TIME
    const cookieDateValid = cookieDateDiff < this.SESSION_TIME;

    return sessionDateValid && hashValid && cookieDateValid;
  }
Example #6
Source File: index.ts    From solita with Apache License 2.0 6 votes vote down vote up
/**
 * Calculates and returns a unique 8 byte discriminator prepended to all
 * accounts.
 *
 * @param name The name of the account to calculate the discriminator.
 */
export function accountDiscriminator(name: string): Buffer {
  return Buffer.from(
    sha256.digest(`account:${camelcase(name, { pascalCase: true })}`)
  ).slice(0, ACCOUNT_DISCRIMINATOR_SIZE)
}
Example #7
Source File: ɵmanifest-registry.ts    From scion-microfrontend-platform with Eclipse Public License 2.0 6 votes vote down vote up
public registerCapability(capability: Capability, appSymbolicName: string): string {
    if (!capability) {
      throw Error('[CapabilityRegisterError] Missing required capability.');
    }
    if (capability.qualifier && capability.qualifier.hasOwnProperty('*')) {
      throw Error('[CapabilityRegisterError] Asterisk wildcard (\'*\') not allowed in the qualifier key.');
    }

    // use the first 7 digits of the capability hash as capability id
    const capabilityId = sha256(JSON.stringify({application: appSymbolicName, type: capability.type, ...capability.qualifier})).substring(0, 7);
    const capabilityToRegister: Capability = {
      ...capability,
      qualifier: capability.qualifier ?? {},
      params: coerceCapabilityParamDefinitions(capability, appSymbolicName),
      requiredParams: undefined,
      optionalParams: undefined,
      private: capability.private ?? true,
      metadata: {
        id: capabilityId,
        appSymbolicName: appSymbolicName,
      },
    };

    // Register the capability.
    this._capabilityStore.add(capabilityToRegister);
    return capabilityId;
  }
Example #8
Source File: ɵmanifest-registry.ts    From scion-microfrontend-platform with Eclipse Public License 2.0 6 votes vote down vote up
public registerIntention(intention: Intention, appSymbolicName: string): string {
    if (!intention) {
      throw Error(`[IntentionRegisterError] Missing required intention.`);
    }

    // use the first 7 digits of the intention hash as intention id
    const intentionId = sha256(JSON.stringify({application: appSymbolicName, type: intention.type, ...intention.qualifier})).substring(0, 7);
    const intentionToRegister: Intention = {
      ...intention,
      metadata: {
        id: intentionId,
        appSymbolicName: appSymbolicName,
      },
    };

    // Register the intention.
    this._intentionStore.add(intentionToRegister);
    return intentionId;
  }
Example #9
Source File: utils.ts    From helium-js with Apache License 2.0 6 votes vote down vote up
deriveChecksumBits = (entropyBuffer: Buffer | string) => {
  const ENT = entropyBuffer.length * 8
  const CS = ENT / 32
  const hash = sha256.digest(entropyBuffer)

  return bytesToBinary(Array.from(hash)).slice(0, CS)
}
Example #10
Source File: Utils.spec.ts    From helium-js with Apache License 2.0 6 votes vote down vote up
describe('bs58checkEncode', () => {
  it('should encode a publickey payload to b58 address', async () => {
    const { bob } = await usersFixture()
    const address = new Address(0, NetTypes.MAINNET, 1, bob.publicKey)
    const vPayload = Buffer.concat([Buffer.from([0]), address.bin])
    const checksum = sha256(Buffer.from(sha256.digest(vPayload)))
    const checksumBytes = Buffer.alloc(4, checksum, 'hex')
    const result = Buffer.concat([vPayload, checksumBytes])
    const encoded = bs58.encode(result)
    expect(encoded).toBe(bobB58)
  })
})
Example #11
Source File: Utils.spec.ts    From helium-js with Apache License 2.0 6 votes vote down vote up
describe('bs58ToBin', () => {
  it('should carry a bs58 address to bin', async () => {
    const { bob } = await usersFixture()
    const address = new Address(0, NetTypes.MAINNET, 1, bob.publicKey).b58
    const bin = bs58.decode(address)
    const vPayload = bin.slice(0, -4)
    const checksum = Buffer.from(bin.slice(-4))
    const checksumVerify = sha256(Buffer.from(sha256.digest(vPayload)))
    const checksumVerifyBytes = Buffer.alloc(4, checksumVerify, 'hex')
    expect(checksumVerifyBytes).toStrictEqual(checksum)
  })
})
Example #12
Source File: DrawioClientFactory.ts    From vscode-drawio with GNU General Public License v3.0 5 votes vote down vote up
private async getPlugins(
		config: DiagramConfig
	): Promise<{ jsCode: string }[]> {
		const pluginsToLoad = new Array<{ jsCode: string }>();
		const promises = new Array<Promise<void>>();

		for (const ext of getDrawioExtensions()) {
			promises.push(
				(async () => {
					pluginsToLoad.push(
						...(await ext.getDrawioPlugins({ uri: config.uri }))
					);
				})()
			);
		}

		for (const p of config.plugins) {
			let jsCode: string;
			try {
				jsCode = BufferImpl.from(
					await workspace.fs.readFile(p.file)
				).toString("utf-8");
			} catch (e) {
				window.showErrorMessage(
					`Could not read plugin file "${p.file}"!`
				);
				continue;
			}

			const fingerprint = sha256.hex(jsCode);
			const pluginId = p.file.toString();

			const isAllowed = this.config.isPluginAllowed(
				pluginId,
				fingerprint
			);
			if (isAllowed) {
				pluginsToLoad.push({ jsCode });
			} else if (isAllowed === undefined) {
				promises.push(
					(async () => {
						const result = await window.showWarningMessage(
							`Found unknown plugin "${pluginId}" with fingerprint "${fingerprint}"`,
							{},
							{
								title: "Allow",
								action: async () => {
									pluginsToLoad.push({ jsCode });
									await this.config.addKnownPlugin(
										pluginId,
										fingerprint,
										true
									);
								},
							},
							{
								title: "Disallow",
								action: async () => {
									await this.config.addKnownPlugin(
										pluginId,
										fingerprint,
										false
									);
								},
							}
						);

						if (result) {
							await result.action();
						}
					})()
				);
			}
		}

		await Promise.all(promises);
		return pluginsToLoad;
	}
Example #13
Source File: index.ts    From solita with Apache License 2.0 5 votes vote down vote up
function sighash(nameSpace: string, ixName: string): Buffer {
  let name = snakeCase(ixName)
  let preimage = `${nameSpace}:${name}`
  return Buffer.from(sha256.digest(preimage)).slice(0, 8)
}
Example #14
Source File: helpers.ts    From chain-js with MIT License 5 votes vote down vote up
/** Generates a SHA256 hash from a string value
 *  Returns a hex-encoded result */
export function createSha256Hash(value: string) {
  const hash = sha256.create()
  hash.update(value)
  return hash.hex()
}
Example #15
Source File: Auth.ts    From companion-kit with MIT License 5 votes vote down vote up
async signInWithApple(): Promise<boolean> {
        return this.doInitialization(async () => {
            try {
                this.setNextProvider(AuthProviders.Apple);
                const rawNonce = (Date.now() * Math.random()).toString(36);

                const credential = await AppleAuthentication.signInAsync({
                    requestedScopes: [
                        AppleAuthentication.AppleAuthenticationScope.FULL_NAME,
                        AppleAuthentication.AppleAuthenticationScope.EMAIL,
                    ],
                    nonce: sha256(rawNonce),
                });

                const authCredential = new Firebase.Instance.FirebaseAuth.OAuthProvider('apple.com')
                    .credential({
                        idToken: credential.identityToken,
                        rawNonce: rawNonce,
                    });

                try {
                    await Firebase.Instance.auth.signInWithCredential(authCredential);
                } catch (e) {
                    logger.error(e);
                    throw e;
                }

                // signed in
                logger.log('APPLE SIGN IN RESULT:', credential);

                return true;
            } catch (e) {
                this.setNextProvider(AuthProviders.None);

                if (e.code === 'ERR_CANCELED') {
                    // handle that the user canceled the sign-in flow
                    logger.warn('user canceled the sign-in flow:', e);
                } else {
                    // handle other errors
                    logger.warn('APPLE SIGN IN ERROR:', e);
                }

                return false;
            }
        });
    }
Example #16
Source File: akashSync.ts    From akashlytics with GNU General Public License v3.0 4 votes vote down vote up
async function insertBlocks(startHeight, endHeight) {
  const blockCount = endHeight - startHeight + 1;
  console.log("Inserting " + blockCount + " blocks into database");
  syncingStatus = "Inserting blocks";

  let lastInsertedBlock = (await Block.findOne({
    include: [
      {
        model: Day,
        required: true
      }
    ],
    order: [["height", "DESC"]]
  })) as any;

  let blocksToAdd = [];
  let txsToAdd = [];
  let msgsToAdd = [];

  for (let i = startHeight; i <= endHeight; ++i) {
    syncingStatus = `Inserting block #${i} / ${endHeight}`;

    const blockData = await getCachedBlockByHeight(i);

    if (!blockData) throw "Block # " + i + " was not in cache";

    let msgIndexInBlock = 0;
    const blockDatetime = new Date(blockData.block.header.time);

    const txs = blockData.block.data.txs;
    for (let txIndex = 0; txIndex < txs.length; ++txIndex) {
      const tx = txs[txIndex];
      const hash = sha256(Buffer.from(tx, "base64")).toUpperCase();
      const txId = uuid.v4();

      let hasInterestingTypes = false;
      const decodedTx = decodeTxRaw(fromBase64(tx));
      const msgs = decodedTx.body.messages;

      for (let msgIndex = 0; msgIndex < msgs.length; ++msgIndex) {
        const msg = msgs[msgIndex];
        const isInterestingType = Object.keys(messageHandlers).includes(msg.typeUrl);

        msgsToAdd.push({
          id: uuid.v4(),
          txId: txId,
          type: msg.typeUrl,
          typeCategory: msg.typeUrl.split(".")[0].substring(1),
          index: msgIndex,
          height: i,
          indexInBlock: msgIndexInBlock++,
          isInterestingType: isInterestingType
        });

        if (isInterestingType) {
          hasInterestingTypes = true;
        }
      }

      txsToAdd.push({
        id: txId,
        hash: hash,
        height: i,
        index: txIndex,
        hasInterestingTypes: hasInterestingTypes
      });
    }

    const blockEntry = {
      height: i,
      datetime: new Date(blockData.block.header.time),
      totalTxCount: (lastInsertedBlock?.totalTxCount || 0) + txs.length,
      dayId: lastInsertedBlock?.dayId,
      day: lastInsertedBlock?.day
    };

    const blockDate = new Date(Date.UTC(blockDatetime.getUTCFullYear(), blockDatetime.getUTCMonth(), blockDatetime.getUTCDate()));

    if (!lastInsertedBlock || !isEqual(blockDate, lastInsertedBlock.day.date)) {
      console.log("Creating day: ", blockDate, i);
      const newDay = await Day.create({
        id: uuid.v4(),
        date: blockDate,
        firstBlockHeight: i,
        lastBlockHeightYet: i
      });

      blockEntry.dayId = newDay.id;
      blockEntry.day = newDay;

      if (lastInsertedBlock) {
        lastInsertedBlock.day.lastBlockHeight = lastInsertedBlock.height;
        lastInsertedBlock.day.lastBlockHeightYet = lastInsertedBlock.height;
        await lastInsertedBlock.day.save();
      }
    }
    lastInsertedBlock = blockEntry;

    blocksToAdd.push(blockEntry);

    if (blocksToAdd.length >= 1_000 || i === endHeight) {
      await Block.bulkCreate(blocksToAdd);
      await Transaction.bulkCreate(txsToAdd);
      await Message.bulkCreate(msgsToAdd);

      blocksToAdd = [];
      txsToAdd = [];
      msgsToAdd = [];
      console.log(`Blocks added to db: ${i - startHeight + 1} / ${blockCount} (${(((i - startHeight + 1) * 100) / blockCount).toFixed(2)}%)`);

      if (lastInsertedBlock) {
        lastInsertedBlock.day.lastBlockHeightYet = lastInsertedBlock.height;
        await lastInsertedBlock.day.save();
      }
    }
  }

  let totalBlockCount = await Block.count();
  let totalTxCount = await Transaction.count();
  let totalMsgCount = await Message.count();

  console.log("Total: ");
  console.table([{ totalBlockCount, totalTxCount, totalMsgCount }]);
}
Example #17
Source File: apolloServer.spec.ts    From apollo-server-vercel with MIT License 4 votes vote down vote up
describe(`apolloServer`, () => {
  let app = null as ReturnType<typeof createApp>;
  let didEncounterErrors: jest.Mock<
    ReturnType<GraphQLRequestListener["didEncounterErrors"]>,
    Parameters<GraphQLRequestListener["didEncounterErrors"]>
  >;

  afterEach(() => {
    if (app) {
      app = null;
    }
  });

  describe(`graphqlHTTP`, () => {
    it(`rejects the request if the method is not POST or GET`, async () => {
      app = createApp();
      const res = await request(app).head(`/graphql`).send();
      expect(res.status).toStrictEqual(405);
      expect(res.header.allow).toStrictEqual(`GET, POST`);
    });

    it(`throws an error if POST body is missing`, async () => {
      app = createApp();
      const res = await request(app).post(`/graphql`).send();
      expect(res.status).toStrictEqual(500);
      expect((res.error as HTTPError).text).toMatch(`POST body missing.`);
    });

    it(`throws an error if GET query is missing`, async () => {
      app = createApp();
      const res = await request(app).get(`/graphql`);
      expect(res.status).toStrictEqual(400);
      expect((res.error as HTTPError).text).toMatch(`GET query missing.`);
    });

    it(`can handle a basic GET request`, async () => {
      app = createApp();
      const expected = {
        testString: `it works`
      };
      const query = {
        query: `
          query test {
            testString
          }
        `
      };
      const res = await request(app).get(`/graphql`).query(query);
      expect(res.status).toStrictEqual(200);
      expect(res.body.data).toStrictEqual(expected);
    });

    it(`can handle a basic implicit GET request`, async () => {
      app = createApp();
      const expected = {
        testString: `it works`
      };
      const query = {
        query: `
          {
            testString
          }
        `
      };
      const res = await request(app).get(`/graphql`).query(query);
      expect(res.status).toStrictEqual(200);
      expect(res.body.data).toStrictEqual(expected);
    });

    it(`throws error if trying to use mutation using GET request`, async () => {
      didEncounterErrors = jest.fn();
      app = createApp({
        schema,
        plugins: [
          {
            requestDidStart(): { didEncounterErrors: typeof didEncounterErrors } {
              return { didEncounterErrors };
            }
          }
        ]
      });
      const query = {
        query: `
          mutation test {
            testMutation(echo: "ping")
          }
        `
      };
      const res = await request(app).get(`/graphql`).query(query);

      expect(res.status).toStrictEqual(405);
      expect(res.header.allow).toStrictEqual(`POST`);
      expect((res.error as HTTPError).text).toMatch(`GET supports only query operation`);
      expect(didEncounterErrors).toHaveBeenCalledWith(
        expect.objectContaining({
          errors: expect.arrayContaining([
            expect.objectContaining({
              message: `GET supports only query operation`
            })
          ])
        })
      );
    });

    it(`throws error if trying to use mutation with fragment using GET request`, async () => {
      didEncounterErrors = jest.fn();
      app = createApp({
        schema,
        plugins: [
          {
            requestDidStart(): { didEncounterErrors: typeof didEncounterErrors } {
              return { didEncounterErrors };
            }
          }
        ]
      });
      const query = {
        query: `
          fragment PersonDetails on PersonType {
            firstName
          }
          mutation test {
            testPerson(firstName: "Test", lastName: "Me") {
              ...PersonDetails
            }
          }
        `
      };
      const res = await request(app).get(`/graphql`).query(query);
      expect(res.status).toStrictEqual(405);
      expect(res.header.allow).toStrictEqual(`POST`);
      expect((res.error as HTTPError).text).toMatch(`GET supports only query operation`);
      expect(didEncounterErrors).toHaveBeenCalledWith(
        expect.objectContaining({
          errors: expect.arrayContaining([
            expect.objectContaining({
              message: `GET supports only query operation`
            })
          ])
        })
      );
    });

    it(`can handle a GET request with variables`, async () => {
      app = createApp();
      const query = {
        query: `
          query test($echo: String) {
            testArgument(echo: $echo)
          }
        `,
        variables: JSON.stringify({ echo: `world` })
      };
      const expected = {
        testArgument: `hello world`
      };
      const res = await request(app).get(`/graphql`).query(query);
      expect(res.status).toStrictEqual(200);
      expect(res.body.data).toStrictEqual(expected);
    });

    it(`can handle a basic request`, async () => {
      app = createApp();
      const expected = {
        testString: `it works`
      };
      const res = await request(app)
        .post(`/graphql`)
        .send({
          query: `
            query test {
              testString
            }
          `
        });
      expect(res.status).toStrictEqual(200);
      expect(res.body.data).toStrictEqual(expected);
    });

    it(`can handle a basic request with cacheControl`, async () => {
      app = createApp({ schema, cacheControl: true });
      const expected = {
        testPerson: { firstName: `Jane` }
      };
      const res = await request(app)
        .post(`/graphql`)
        .send({
          query: `
            query test {
              testPerson {
                firstName
              }
            }
          `
        });
      expect(res.status).toStrictEqual(200);
      expect(res.body.data).toStrictEqual(expected);
      expect(res.body.extensions).toStrictEqual({
        cacheControl: {
          version: 1,
          hints: [{ maxAge: 0, path: [`testPerson`] }]
        }
      });
    });

    it(`can handle a basic request with cacheControl and defaultMaxAge`, async () => {
      app = createApp({
        schema,
        cacheControl: {
          defaultMaxAge: 5,
          stripFormattedExtensions: false,
          calculateHttpHeaders: false
        }
      });
      const expected = {
        testPerson: { firstName: `Jane` }
      };
      const res = await request(app)
        .post(`/graphql`)
        .send({
          query: `
            query test {
              testPerson {
                firstName
              }
            }
          `
        });
      expect(res.status).toStrictEqual(200);
      expect(res.body.data).toStrictEqual(expected);
      expect(res.body.extensions).toStrictEqual({
        cacheControl: {
          version: 1,
          hints: [{ maxAge: 5, path: [`testPerson`] }]
        }
      });
    });

    it(`returns PersistedQueryNotSupported to a GET request if PQs disabled`, async () => {
      app = createApp({ schema, persistedQueries: false });
      const res = await request(app)
        .get(`/graphql`)
        .query({
          extensions: JSON.stringify({
            persistedQuery: {
              version: 1,
              sha256Hash: `aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa`
            }
          })
        });
      expect(res.status).toStrictEqual(200);
      expect(res.body.errors).toBeDefined();
      expect(res.body.errors[0].message).toStrictEqual(`PersistedQueryNotSupported`);
    });

    it(`returns PersistedQueryNotSupported to a POST request if PQs disabled`, async () => {
      app = createApp({ schema, persistedQueries: false });
      const res = await request(app)
        .post(`/graphql`)
        .send({
          extensions: {
            persistedQuery: {
              version: 1,
              sha256Hash: `aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa`
            }
          }
        });
      expect(res.status).toStrictEqual(200);
      expect(res.body.errors).toBeDefined();
      expect(res.body.errors).toHaveLength(1);
      expect(res.body.errors[0].message).toStrictEqual(`PersistedQueryNotSupported`);
    });

    it(`returns PersistedQueryNotFound to a GET request`, async () => {
      app = createApp();
      const res = await request(app)
        .get(`/graphql`)
        .query({
          extensions: JSON.stringify({
            persistedQuery: {
              version: 1,
              sha256Hash: `aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa`
            }
          })
        });
      expect(res.status).toStrictEqual(200);
      expect(res.body.errors).toBeDefined();
      expect(res.body.errors).toHaveLength(1);
      expect(res.body.errors[0].message).toStrictEqual(`PersistedQueryNotFound`);
    });

    it(`returns PersistedQueryNotFound to a POST request`, async () => {
      app = createApp();
      const res = await request(app)
        .post(`/graphql`)
        .send({
          extensions: {
            persistedQuery: {
              version: 1,
              sha256Hash: `aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa`
            }
          }
        });
      expect(res.status).toStrictEqual(200);
      expect(res.body.errors).toBeDefined();
      expect(res.body.errors).toHaveLength(1);
      expect(res.body.errors[0].message).toStrictEqual(`PersistedQueryNotFound`);
    });

    it(`can handle a request with variables`, async () => {
      app = createApp();
      const expected = {
        testArgument: `hello world`
      };
      const res = await request(app)
        .post(`/graphql`)
        .send({
          query: `
            query test($echo: String) {
              testArgument(echo: $echo)
            }
          `,
          variables: { echo: `world` }
        });
      expect(res.status).toStrictEqual(200);
      expect(res.body.data).toStrictEqual(expected);
    });

    it(`can handle a request with variables as string`, async () => {
      app = createApp();
      const expected = {
        testArgument: `hello world`
      };
      const res = await request(app)
        .post(`/graphql`)
        .send({
          query: `
            query test($echo: String!) {
              testArgument(echo: $echo)
            }
          `,
          variables: `{ "echo": "world" }`
        });
      expect(res.status).toStrictEqual(200);
      expect(res.body.data).toStrictEqual(expected);
    });

    it(`can handle a request with variables as an invalid string`, async () => {
      app = createApp();
      const res = await request(app)
        .post(`/graphql`)
        .send({
          query: `
            query test($echo: String!) {
              testArgument(echo: $echo)
            }
          `,
          variables: `{ echo: "world" }`
        });
      expect(res.status).toStrictEqual(400);
      expect((res.error as HTTPError).text).toMatch(`Variables are invalid JSON.`);
    });

    it(`can handle a request with operationName`, async () => {
      app = createApp();
      const expected = {
        testString: `it works`
      };
      const res = await request(app)
        .post(`/graphql`)
        .send({
          query: `
            query test($echo: String) {
              testArgument(echo: $echo)
            }
            query test2 {
              testString
            }
          `,
          variables: { echo: `world` },
          operationName: `test2`
        });
      expect(res.status).toStrictEqual(200);
      expect(res.body.data).toStrictEqual(expected);
    });

    it(`can handle introspection request`, async () => {
      app = createApp();
      const res = await request(app).post(`/graphql`).send({ query: getIntrospectionQuery() });
      expect(res.status).toStrictEqual(200);
      expect(res.body.data.__schema.types[0].fields[0].name).toStrictEqual(`testString`);
    });

    it(`does not accept a query AST`, async () => {
      app = createApp();
      const res = await request(app)
        .post(`/graphql`)
        .send({
          query: gql`
            query test {
              testString
            }
          `
        });
      expect(res.status).toStrictEqual(400);
      expect(res.text).toMatch(`GraphQL queries must be strings`);
    });

    it(`can handle batch requests`, async () => {
      app = createApp();
      const expected = [
        {
          data: {
            testString: `it works`
          }
        },
        {
          data: {
            testArgument: `hello yellow`
          }
        }
      ];
      const res = await request(app)
        .post(`/graphql`)
        .send([
          {
            query: `
              query test($echo: String) {
                testArgument(echo: $echo)
              }
              query test2 {
                testString
              }
            `,
            variables: { echo: `world` },
            operationName: `test2`
          },
          {
            query: `
              query testX($echo: String) {
                testArgument(echo: $echo)
              }
            `,
            variables: { echo: `yellow` },
            operationName: `testX`
          }
        ]);
      expect(res.status).toStrictEqual(200);
      expect(res.body).toStrictEqual(expected);
    });

    it(`can handle batch requests 2`, async () => {
      app = createApp();
      const expected = [
        {
          data: {
            testString: `it works`
          }
        }
      ];
      const res = await request(app)
        .post(`/graphql`)
        .send([
          {
            query: `
              query test($echo: String) {
                testArgument(echo: $echo)
              }
              query test2 {
                testString
              }
            `,
            variables: { echo: `world` },
            operationName: `test2`
          }
        ]);
      expect(res.status).toStrictEqual(200);
      expect(res.body).toStrictEqual(expected);
    });

    it(`can handle batch requests in parallel`, async () => {
      const parallels = 100;
      const delayPerReq = 40;

      app = createApp();
      const expected = Array(parallels).fill({
        data: { testStringWithDelay: `it works` }
      });
      const res = await request(app)
        .post(`/graphql`)
        .send(
          Array(parallels).fill({
            query: `
              query test($delay: Int!) {
                testStringWithDelay(delay: $delay)
              }
            `,
            operationName: `test`,
            variables: { delay: delayPerReq }
          })
        );
      expect(res.status).toStrictEqual(200);
      expect(res.body).toStrictEqual(expected);
    }, 3000); // this test will fail due to timeout if running serially.

    it(`clones batch context`, async () => {
      app = createApp({
        schema,
        context: { testField: `expected` }
      });
      const expected = [
        {
          data: {
            testContext: `expected`
          }
        },
        {
          data: {
            testContext: `expected`
          }
        }
      ];
      const res = await request(app)
        .post(`/graphql`)
        .send([
          {
            query: `
              query test {
                testContext
              }
            `
          },
          {
            query: `
              query test {
                testContext
              }
            `
          }
        ]);
      expect(res.status).toStrictEqual(200);
      expect(res.body).toStrictEqual(expected);
    });

    it(`executes batch context if it is a function`, async () => {
      let callCount = 0;
      app = createApp({
        schema,
        context: () => {
          callCount++;
          return { testField: `expected` };
        }
      });
      const expected = [
        {
          data: {
            testContext: `expected`
          }
        },
        {
          data: {
            testContext: `expected`
          }
        }
      ];
      const res = await request(app)
        .post(`/graphql`)
        .send([
          {
            query: `
              query test {
                testContext
              }
            `
          },
          {
            query: `
              query test {
                testContext
              }
            `
          }
        ]);
      // XXX In AS 1.0 we ran context once per GraphQL operation (so this
      // was 2) rather than once per HTTP request. Was this actually
      // helpful? Honestly we're not sure why you'd use a function in the
      // 1.0 API anyway since the function didn't actually get any useful
      // arguments. Right now there's some weirdness where a context
      // function is actually evaluated both inside ApolloServer and in
      // runHttpQuery.
      expect(callCount).toStrictEqual(1);
      expect(res.status).toStrictEqual(200);
      expect(res.body).toStrictEqual(expected);
    });

    it(`can handle a request with a mutation`, async () => {
      app = createApp();
      const expected = {
        testMutation: `not really a mutation, but who cares: world`
      };
      const res = await request(app)
        .post(`/graphql`)
        .send({
          query: `
            mutation test($echo: String) {
              testMutation(echo: $echo)
            }
          `,
          variables: { echo: `world` }
        });
      expect(res.status).toStrictEqual(200);
      expect(res.body.data).toStrictEqual(expected);
    });

    it(`applies the formatResponse function`, async () => {
      app = createApp({
        schema,
        formatResponse(response) {
          response.extensions = { it: `works` };
          return response;
        }
      });
      const expected = { it: `works` };
      const res = await request(app)
        .post(`/graphql`)
        .send({
          query: `
            mutation test($echo: String) {
              testMutation(echo: $echo)
            }
          `,
          variables: { echo: `world` }
        });
      expect(res.status).toStrictEqual(200);
      expect(res.body.extensions).toStrictEqual(expected);
    });

    it(`passes the context to the resolver`, async () => {
      const expected = `context works`;
      app = createApp({
        schema,
        context: { testField: expected }
      });
      const res = await request(app)
        .post(`/graphql`)
        .send({
          query: `
            query test {
              testContext
            }
          `
        });
      expect(res.status).toStrictEqual(200);
      expect(res.body.data.testContext).toStrictEqual(expected);
    });

    it(`passes the rootValue to the resolver`, async () => {
      const expected = `it passes rootValue`;
      app = createApp({
        schema,
        rootValue: expected
      });
      const res = await request(app)
        .post(`/graphql`)
        .send({
          query: `
            query test {
              testRootValue
            }
          `
        });
      expect(res.status).toStrictEqual(200);
      expect(res.body.data.testRootValue).toStrictEqual(expected);
    });

    it(`passes the rootValue function result to the resolver for query`, async () => {
      const expectedQuery = `query: it passes rootValue`;
      app = createApp({
        schema,
        rootValue: () => expectedQuery
      });
      const queryRes = await request(app)
        .post(`/graphql`)
        .send({
          query: `
            query test {
              testRootValue
            }
          `
        });
      expect(queryRes.status).toStrictEqual(200);
      expect(queryRes.body.data.testRootValue).toStrictEqual(expectedQuery);
    });

    it(`passes the rootValue function result to the resolver for mutation`, async () => {
      const expectedMutation = `mutation: it passes rootValue`;
      app = createApp({
        schema,
        rootValue: () => expectedMutation
      });
      const res = await request(app)
        .post(`/graphql`)
        .send({
          query: `
            mutation test {
              testRootValue
            }
          `
        });
      res.body; //?
      expect(res.status).toStrictEqual(200);
      expect(res.body.data.testRootValue).toStrictEqual(expectedMutation);
    });

    it(`returns errors`, async () => {
      const expected = `Secret error message`;
      app = createApp({
        schema
      });
      const res = await request(app)
        .post(`/graphql`)
        .send({
          query: `
            query test {
              testError
            }
          `
        });
      expect(res.status).toStrictEqual(200);
      expect(res.body.errors[0].message).toStrictEqual(expected);
    });

    it(`applies formatError if provided`, async () => {
      const expected = `--blank--`;
      app = createApp({
        schema,
        formatError: (error) => {
          expect(error instanceof Error).toBe(true);
          return { message: expected };
        }
      });
      const res = await request(app)
        .post(`/graphql`)
        .send({
          query: `
            query test {
              testError
            }
          `
        });
      expect(res.status).toStrictEqual(200);
      expect(res.body.errors[0].message).toStrictEqual(expected);
    });

    it(`formatError receives error that passes instanceof checks`, async () => {
      const expected = `--blank--`;
      app = createApp({
        schema,
        formatError: (error) => {
          expect(error instanceof Error).toBe(true);
          expect(error instanceof GraphQLError).toBe(true);
          return { message: expected };
        }
      });
      const res = await request(app)
        .post(`/graphql`)
        .send({
          query: `
            query test {
              testError
            }
          `
        });
      expect(res.status).toStrictEqual(200);
      expect(res.body.errors[0].message).toStrictEqual(expected);
    });

    it(`allows for custom error formatting to sanitize`, async () => {
      app = createApp({
        schema: TestSchema,
        formatError(error) {
          return { message: `Custom error format: ${error.message}` };
        }
      });

      const res = await request(app)
        .post(`/graphql`)
        .send({
          query: `
            {
              thrower
            }
          `
        });

      expect(res.status).toStrictEqual(200);
      expect(JSON.parse(res.text)).toStrictEqual({
        data: null,
        errors: [
          {
            message: `Custom error format: Throws!`
          }
        ]
      });
    });

    it(`allows for custom error formatting to elaborate`, async () => {
      app = createApp({
        schema: TestSchema,
        formatError(error) {
          return {
            message: error.message,
            locations: error.locations,
            stack: `Stack trace`
          };
        }
      });

      const res = await request(app)
        .post(`/graphql`)
        .send({
          query: `
            {
              thrower
            }
          `
        });

      expect(res.status).toStrictEqual(200);
      expect(JSON.parse(res.text)).toStrictEqual({
        data: null,
        errors: [
          {
            message: `Throws!`,
            locations: [{ line: 3, column: 15 }],
            stack: `Stack trace`
          }
        ]
      });
    });

    it(`sends internal server error when formatError fails`, async () => {
      app = createApp({
        schema,
        formatError: () => {
          throw new Error(`I should be caught`);
        }
      });
      const res = await request(app)
        .post(`/graphql`)
        .send({
          query: `
            query test {
              testError
            }
          `
        });
      expect(res.body.errors[0].message).toStrictEqual(`Internal server error`);
    });

    it(`applies additional validationRules`, async () => {
      const expected = `alwaysInvalidRule was really invalid!`;
      const alwaysInvalidRule = (context): { enter: () => unknown } => ({
        enter(): unknown {
          context.reportError(new GraphQLError(expected));
          return BREAK;
        }
      });
      app = createApp({
        schema,
        validationRules: [alwaysInvalidRule]
      });
      const res = await request(app)
        .post(`/graphql`)
        .send({
          query: `
            query test {
              testString
            }
          `
        });
      expect(res.status).toStrictEqual(400);
      expect(res.body.errors[0].message).toStrictEqual(expected);
    });
  });

  describe(`server setup`, () => {
    it(`throws error on 404 routes`, async () => {
      app = createApp();

      const query = {
        query: `
          {
            testString
          }
        `
      };
      const res = await request(app).get(`/bogus-route`).query(query);
      expect(res.status).toStrictEqual(404);
    });
  });

  describe(`Persisted Queries`, () => {
    const query = `{testString}`;
    const query2 = `{ testString }`;

    const hash = sha256.create().update(query).hex();
    const extensions = {
      persistedQuery: {
        version: VERSION,
        sha256Hash: hash
      }
    };

    const extensions2 = {
      persistedQuery: {
        version: VERSION,
        sha256Hash: sha256.create().update(query2).hex()
      }
    };

    const createMockCache = (): KeyValueCache => {
      const map = new Map<string, string>();
      return {
        set: jest.fn(async (key, val) => {
          // eslint-disable-next-line @typescript-eslint/await-thenable
          await map.set(key, val);
        }),
        // eslint-disable-next-line @typescript-eslint/require-await
        get: jest.fn(async (key) => map.get(key)),
        // eslint-disable-next-line @typescript-eslint/require-await
        delete: jest.fn(async (key) => map.delete(key))
      };
    };

    // eslint-disable-next-line @typescript-eslint/no-shadow
    let didEncounterErrors: jest.Mock<
      ReturnType<GraphQLRequestListener["didEncounterErrors"]>,
      Parameters<GraphQLRequestListener["didEncounterErrors"]>
    >;

    let didResolveSource: jest.Mock<
      ReturnType<GraphQLRequestListener["didResolveSource"]>,
      Parameters<GraphQLRequestListener["didResolveSource"]>
    >;

    let cache: KeyValueCache;

    const createApqApp = (apqOptions: PersistedQueryOptions = {}): ReturnType<typeof createApp> =>
      createApp({
        schema,
        plugins: [
          {
            requestDidStart() {
              return {
                didResolveSource,
                didEncounterErrors
              };
            }
          }
        ],
        persistedQueries: {
          cache,
          ...apqOptions
        }
      });

    beforeEach(() => {
      cache = createMockCache();
      didResolveSource = jest.fn();
      didEncounterErrors = jest.fn();
    });

    it(`when ttlSeconds is set, passes ttl to the apq cache set call`, async () => {
      app = createApqApp({ ttl: 900 });

      await request(app).post(`/graphql`).send({
        extensions,
        query
      });

      // eslint-disable-next-line @typescript-eslint/unbound-method
      expect(cache.set).toHaveBeenCalledWith(
        expect.stringMatching(/^apq:/),
        query,
        expect.objectContaining({
          ttl: 900
        })
      );
      expect(didResolveSource.mock.calls[0][0]).toHaveProperty(`source`, query);
    });

    it(`when ttlSeconds is unset, ttl is not passed to apq cache`, async () => {
      app = createApqApp();

      await request(app).post(`/graphql`).send({
        extensions,
        query
      });

      // eslint-disable-next-line @typescript-eslint/unbound-method
      expect(cache.set).toHaveBeenCalledWith(
        expect.stringMatching(/^apq:/),
        `{testString}`,
        expect.not.objectContaining({
          ttl: 900
        })
      );
      expect(didResolveSource.mock.calls[0][0]).toHaveProperty(`source`, query);
    });

    it(`errors when version is not specified`, async () => {
      app = createApqApp();

      const result = await request(app)
        .get(`/graphql`)
        .query({
          query,
          extensions: JSON.stringify({
            persistedQuery: {
              // Version intentionally omitted.
              sha256Hash: extensions.persistedQuery.sha256Hash
            }
          })
        });

      expect(result).toMatchObject({
        status: 400,
        // Different integrations' response text varies in format.
        text: expect.stringContaining(`Unsupported persisted query version`),
        req: expect.objectContaining({
          method: `GET`
        })
      });

      expect(didEncounterErrors).toHaveBeenCalledWith(
        expect.objectContaining({
          errors: expect.arrayContaining([
            expect.objectContaining({
              message: `Unsupported persisted query version`
            })
          ])
        })
      );
    });

    it(`errors when version is unsupported`, async () => {
      app = createApqApp();

      const result = await request(app)
        .get(`/graphql`)
        .query({
          query,
          extensions: JSON.stringify({
            persistedQuery: {
              // Version intentionally wrong.
              version: VERSION + 1,
              sha256Hash: extensions.persistedQuery.sha256Hash
            }
          })
        });

      expect(result).toMatchObject({
        status: 400,
        // Different integrations' response text varies in format.
        text: expect.stringContaining(`Unsupported persisted query version`),
        req: expect.objectContaining({
          method: `GET`
        })
      });

      expect(didEncounterErrors).toHaveBeenCalledWith(
        expect.objectContaining({
          errors: expect.arrayContaining([
            expect.objectContaining({
              message: `Unsupported persisted query version`
            })
          ])
        })
      );
    });

    it(`errors when hash is mismatched`, async () => {
      app = createApqApp();

      const result = await request(app)
        .get(`/graphql`)
        .query({
          query,
          extensions: JSON.stringify({
            persistedQuery: {
              version: 1,
              // Sha intentionally wrong.
              sha256Hash: extensions.persistedQuery.sha256Hash.substr(0, 5)
            }
          })
        });

      expect(result).toMatchObject({
        status: 400,
        // Different integrations' response text varies in format.
        text: expect.stringContaining(`provided sha does not match query`),
        req: expect.objectContaining({
          method: `GET`
        })
      });

      expect(didEncounterErrors).toHaveBeenCalledWith(
        expect.objectContaining({
          errors: expect.arrayContaining([
            expect.objectContaining({
              message: `provided sha does not match query`
            })
          ])
        })
      );

      expect(didResolveSource).not.toHaveBeenCalled();
    });

    it(`returns PersistedQueryNotFound on the first try`, async () => {
      app = createApqApp();

      const res = await request(app).post(`/graphql`).send({
        extensions
      });

      expect(res.body.data).toBeUndefined();
      expect(res.body.errors).toHaveLength(1);
      expect(res.body.errors[0].message).toStrictEqual(`PersistedQueryNotFound`);
      expect(res.body.errors[0].extensions.code).toStrictEqual(`PERSISTED_QUERY_NOT_FOUND`);

      expect(didEncounterErrors).toHaveBeenCalledWith(
        expect.objectContaining({
          errors: expect.arrayContaining([expect.any(PersistedQueryNotFoundError)])
        })
      );

      expect(didResolveSource).not.toHaveBeenCalled();
    });

    it(`returns result on the second try`, async () => {
      app = createApqApp();

      await request(app).post(`/graphql`).send({
        extensions
      });

      // Only the first request should result in an error.
      expect(didEncounterErrors).toHaveBeenCalledTimes(1);
      expect(didEncounterErrors).toHaveBeenCalledWith(
        expect.objectContaining({
          errors: expect.arrayContaining([expect.any(PersistedQueryNotFoundError)])
        })
      );

      expect(didResolveSource).not.toHaveBeenCalled();

      const result = await request(app).post(`/graphql`).send({
        extensions,
        query
      });

      // There should be no additional errors now.  In other words, we'll
      // re-assert that we've been called the same single time that we
      // asserted above.
      expect(didEncounterErrors).toHaveBeenCalledTimes(1);

      expect(didResolveSource.mock.calls[0][0]).toHaveProperty(`source`, query);

      expect(result.body.data).toStrictEqual({ testString: `it works` });
      expect(result.body.errors).toBeUndefined();
    });

    it(`returns with batched persisted queries`, async () => {
      app = createApqApp();

      const errors = await request(app)
        .post(`/graphql`)
        .send([
          {
            extensions
          },
          {
            extensions: extensions2
          }
        ]);

      expect(errors.body[0].data).toBeUndefined();
      expect(errors.body[1].data).toBeUndefined();
      expect(errors.body[0].errors[0].message).toStrictEqual(`PersistedQueryNotFound`);
      expect(errors.body[0].errors[0].extensions.code).toStrictEqual(`PERSISTED_QUERY_NOT_FOUND`);
      expect(errors.body[1].errors[0].message).toStrictEqual(`PersistedQueryNotFound`);
      expect(errors.body[1].errors[0].extensions.code).toStrictEqual(`PERSISTED_QUERY_NOT_FOUND`);

      const result = await request(app)
        .post(`/graphql`)
        .send([
          {
            extensions,
            query
          },
          {
            extensions: extensions2,
            query: query2
          }
        ]);

      expect(result.body[0].data).toStrictEqual({ testString: `it works` });
      expect(result.body[0].data).toStrictEqual({ testString: `it works` });
      expect(result.body.errors).toBeUndefined();
    });

    it(`returns result on the persisted query`, async () => {
      app = createApqApp();

      await request(app).post(`/graphql`).send({
        extensions
      });

      expect(didResolveSource).not.toHaveBeenCalled();

      await request(app).post(`/graphql`).send({
        extensions,
        query
      });
      const res = await request(app).post(`/graphql`).send({
        extensions
      });

      expect(didResolveSource.mock.calls[0][0]).toHaveProperty(`source`, query);

      expect(res.body.data).toStrictEqual({ testString: `it works` });
      expect(res.body.errors).toBeUndefined();
    });

    it(`returns error when hash does not match`, async () => {
      app = createApqApp();

      const res = await request(app)
        .post(`/graphql`)
        .send({
          extensions: {
            persistedQuery: {
              version: VERSION,
              sha: `aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa`
            }
          },
          query
        });
      expect(res.status).toStrictEqual(400);
      expect((res.error as HTTPError).text).toMatch(/does not match query/);
      expect(didResolveSource).not.toHaveBeenCalled();
    });

    it(`returns correct result using get request`, async () => {
      app = createApqApp();

      await request(app).post(`/graphql`).send({
        extensions,
        query
      });
      const result = await request(app)
        .get(`/graphql`)
        .query({
          extensions: JSON.stringify(extensions)
        });
      expect(result.body.data).toStrictEqual({ testString: `it works` });
      expect(didResolveSource.mock.calls[0][0]).toHaveProperty(`source`, query);
    });
  });
});