Mirror: A maybe slightly safer-ish wrapper around eval Function constructors

Compare changes

Choose any two refs to compare.

Changed files
+52 -4
.github
workflows
src
+26
.github/workflows/mirror.yml
··· 1 + # Mirrors to https://tangled.sh/@kitten.sh (knot.kitten.sh) 2 + name: Mirror (Git Backup) 3 + on: 4 + push: 5 + branches: 6 + - main 7 + jobs: 8 + mirror: 9 + runs-on: ubuntu-latest 10 + steps: 11 + - name: Checkout repository 12 + uses: actions/checkout@v4 13 + with: 14 + fetch-depth: 0 15 + fetch-tags: true 16 + - name: Mirror 17 + env: 18 + MIRROR_SSH_KEY: ${{ secrets.MIRROR_SSH_KEY }} 19 + GIT_SSH_COMMAND: 'ssh -o StrictHostKeyChecking=yes' 20 + run: | 21 + mkdir -p ~/.ssh 22 + echo "$MIRROR_SSH_KEY" > ~/.ssh/id_rsa 23 + chmod 600 ~/.ssh/id_rsa 24 + ssh-keyscan -H knot.kitten.sh >> ~/.ssh/known_hosts 25 + git remote add mirror "git@knot.kitten.sh:kitten.sh/${GITHUB_REPOSITORY#*/}" 26 + git push --mirror mirror
+1 -1
package.json
··· 2 2 "name": "evalish", 3 3 "description": "A maybe slightly safer-ish wrapper around eval Function constructors", 4 4 "DISCLAIMER": "Please maybe try something else first.. Please.", 5 - "version": "0.1.7", 5 + "version": "0.1.8", 6 6 "main": "dist/evalish.js", 7 7 "module": "dist/evalish.mjs", 8 8 "types": "dist/types/index.d.ts",
+25 -3
src/index.ts
··· 25 25 const _getOwnPropertyDescriptor = Object.getOwnPropertyDescriptor; 26 26 const _defineProperty = Object.defineProperty; 27 27 const _create = Object.create; 28 + const _slice = Array.prototype.slice; 28 29 29 30 type Object = Record<string | symbol, unknown>; 30 31 ··· 75 76 if (new.target === undefined) { 76 77 return target.apply(this, arguments); 77 78 } else { 78 - return new (target.bind.apply(target, arguments)); 79 + const args = _slice.call(arguments); 80 + args.unshift(null); 81 + return new (target.bind.apply(target, args)); 79 82 } 80 83 }) 81 84 : _create(null); ··· 131 134 standin.prototype = _create(null); 132 135 } 133 136 134 - return freeze(standin); 137 + return toplevel ? standin : freeze(standin); 135 138 } 136 139 137 140 let safeGlobal: Record<string | symbol, unknown> | void; ··· 208 211 209 212 // Lastly, we also disallow certain property accesses on the safe global 210 213 // Wrap any given target with a Proxy preventing access to unscopables 211 - return freeze(safeGlobal!); 214 + if (typeof Proxy === 'function') { 215 + // Wrap the target in a Proxy that disallows access to some keys 216 + return (safeGlobal = new Proxy(safeGlobal!, { 217 + // Return a value, if it's allowed to be returned and mask this value 218 + get(target, _key) { 219 + const key = safeKey(target, _key); 220 + return !ignore[_key] && key !== undefined ? target[key] : undefined; 221 + }, 222 + has(_target, _key) { 223 + return true; 224 + }, 225 + set: noop, 226 + deleteProperty: noop, 227 + defineProperty: noop, 228 + getOwnPropertyDescriptor: noop, 229 + })); 230 + } else { 231 + // NOTE: Some property accesses may leak through here without the Proxy 232 + return freeze(safeGlobal!); 233 + } 212 234 } 213 235 214 236 interface SafeFunction {