Watch
1
0
Fork
You've already forked ungoogle
0
decode google /goto redirector as math allows
  • TypeScript 91.7%
  • JavaScript 8.3%
Find a file
Repository files (latest commit first)
Filename Latest commit message Latest commit date
2026-09-14 19:55:16 +03:00
src feat: initial 2026-09-14 19:55:16 +03:00
test feat: initial 2026-09-14 19:55:16 +03:00
.gitignore feat: initial 2026-09-14 19:55:16 +03:00
eslint.config.js feat: initial 2026-09-14 19:55:16 +03:00
jest.config.js feat: initial 2026-09-14 19:55:16 +03:00
package.json feat: initial 2026-09-14 19:55:16 +03:00
pnpm-lock.yaml feat: initial 2026-09-14 19:55:16 +03:00
pnpm-workspace.yaml feat: initial 2026-09-14 19:55:16 +03:00
README.md feat: initial 2026-09-14 19:55:16 +03:00
tsconfig.json feat: initial 2026-09-14 19:55:16 +03:00

ungoogle

decodes google's /goto?url= redirector links as far as the math allows

the format

payload := base64url( protobuf {
    1: varint   format version, currently 1, ignored by the server
    2: bytes    tink aead box
})

box := 0x01 | keyId[4] | nonce[12] | aes-gcm(plaintext) | tag[16]

the plaintext is a small protobuf holding the target url plus a constant 23-byte tail (click id and timestamp), sealed with a key that never leaves google's keyset

aaand across the sample links the key id 0xEB3B3015 is shared and the nonces are unique, so there is no nonce-reuse shortcut either

usage

import { decodePacket, findGotoLinks, formatPacket } from 'ungoogle'

const packet = decodePacket('https://www.google.com/goto?url=CAESVAHrOzAV...')

packet.version // 1
packet.keyId // 0xEB3B3015
packet.nonce // Uint8Array(12)
packet.ciphertext // Uint8Array(51)
packet.tag // Uint8Array(16)
packet.targetLength // 28, derived from the ciphertext size
packet.payload // the bare base64url blob

console.log(formatPacket(packet))
findGotoLinks(something) // every /goto link in a blob of text

dev

pnpm i
pnpm build
pnpm lint
pnpm test