Skip to content

Built for people who want to own their automations. Join the waitlist for an invite.

Package listing

@kentcdodds/github

src/actions/sealed-box.ts

37 lines · 1.2 KB · TypeScript
import nacl from 'tweetnacl'
import sealedBox from 'tweetnacl-sealedbox-js'

/**
 * Encrypt a GitHub Actions secret with the repo public key.
 *
 * GitHub's Actions secrets API expects a libsodium sealed box. The previous
 * working path in this account used `tweetnacl-sealedbox-js` because
 * `libsodium-wrappers` WASM is blocked in Kody execute.
 */
export function sealActionsSecret(plaintext: string, publicKeyBase64: string) {
	const publicKey = decodeBase64(publicKeyBase64)
	if (publicKey.byteLength !== nacl.box.publicKeyLength) {
		throw new Error(
			`GitHub Actions public key must be ${nacl.box.publicKeyLength} bytes, got ${publicKey.byteLength}`,
		)
	}
	const sealed = sealedBox.seal(new TextEncoder().encode(plaintext), publicKey)
	return encodeBase64(sealed)
}

export function decodeBase64(value: string) {
	const binary = atob(value)
	const bytes = new Uint8Array(binary.length)
	for (let index = 0; index < binary.length; index += 1) {
		bytes[index] = binary.charCodeAt(index)
	}
	return bytes
}

export function encodeBase64(bytes: Uint8Array) {
	let binary = ''
	for (const byte of bytes) {
		binary += String.fromCharCode(byte)
	}
	return btoa(binary)
}