Skip to content

Commit

Permalink
feat: Ignore patterns
Browse files Browse the repository at this point in the history
  • Loading branch information
franky47 committed Dec 25, 2022
1 parent 262eaed commit bf523f4
Show file tree
Hide file tree
Showing 4 changed files with 48 additions and 34 deletions.
6 changes: 6 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,12 @@ $ sceau sign --packageDir packages/my-package --file build/signature.json
This will sign package `<cwd>/packages/my-package`, and store the output at
`<cwd>/packages/my-package/build/signature.json`.

`--ignore` lets you specify RegExp patterns to match against file paths.
Files matching those patterns won't be included in the manifest and therefore
won't be part of the final signature.

Note that the output file is always automatically included in those patterns.

### Verifying

You can verify a package signed with sceau using the following command:
Expand Down
5 changes: 5 additions & 0 deletions src/cli/args.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,10 @@ const signCommandSchema = z.object({
packageDir: z.string().optional(),
file: z.string().optional().default(SCEAU_FILE_NAME),
quiet: z.boolean().optional().default(false),
ignore: z
.union([z.string().transform(str => [str]), z.array(z.string()).optional()])
.optional()
.default([]),
})

export type SignCommandArgs = Omit<z.infer<typeof signCommandSchema>, 'command'>
Expand Down Expand Up @@ -87,6 +91,7 @@ ${chalk.green('##')} ${chalk.bold('sceau sign')}
Options:
--packageDir [path] Path to the package to process (default: \`cwd\`)
--file [path] Store the output into the given JSON file, relative to packageDir (default: \`sceau.json\`)
--ignore [regex] Ignore files matching the regular expression (can be passed multiple times)
--quiet Don't print any output
Expand Down
4 changes: 3 additions & 1 deletion src/cli/commands/sign.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,9 @@ export async function signCommand(args: SignCommandArgs) {
privateKey,
buildURL,
sourceURL,
ignoreFiles: [args.file],
ignorePatterns: [`^${args.file}$`, ...args.ignore].map(
str => new RegExp(str)
),
})
await fs.writeFile(args.file, JSON.stringify(sceau))
if (!args.quiet) {
Expand Down
67 changes: 34 additions & 33 deletions src/lib.ts
Original file line number Diff line number Diff line change
Expand Up @@ -234,13 +234,13 @@ async function verifyManifestEntry(
async function signManifest(
sodium: Sodium,
packageDir: string,
ignoreFiles: string[],
ignorePatterns: RegExp[],
privateKey: Uint8Array
) {
const arborist = new Arborist({ path: packageDir })
const tree = await arborist.loadActual()
const files = (await packlist(tree)).filter(
file => !ignoreFiles.includes(file)
file => !ignorePatterns.some(pattern => pattern.test(file))
)
files.sort()
return Promise.all(
Expand All @@ -266,46 +266,47 @@ async function verifyManifest(
) as ManifestEntryVerificationFailure[]
}

const signInputSchema = sceauSchema
.pick({
sourceURL: true,
buildURL: true,
})
.extend({
timestamp: z.date(),

/**
* Absolute path to the package to sign
*/
packageDir: z.string(),

/**
* Ed25519 private key to use for signature (64 bytes hex encoded)
*/
privateKey: hexStringSchema(64),
/** A list of files to omit from the manifest
*
* Note that this should always include the sceau file itself,
* otherwise signature will be impossible (running in circles).
*/
ignoreFiles: z.array(z.string()).default([]),
})

type SignInput = z.infer<typeof signInputSchema>
type SignInput = Pick<Sceau, 'sourceURL' | 'buildURL'> & {
timestamp: Date
/**
* Absolute path to the package to sign
*/
packageDir: string
/**
* Ed25519 private key to use for signature (64 bytes hex encoded)
*/
privateKey: string
/** A list of files to omit from the manifest
*
* Note that this should always include the sceau file itself,
* otherwise signature will be impossible (running in circles).
*/
ignorePatterns: RegExp[]
}

export async function sign(sodium: Sodium, input: SignInput) {
const { packageDir, sourceURL, buildURL, privateKey, ignoreFiles } =
signInputSchema.parse(input)
export async function sign(
sodium: Sodium,
{
packageDir,
sourceURL,
buildURL,
privateKey,
ignorePatterns,
timestamp: timestampDate,
}: SignInput
) {
// Verify private key format
hexStringSchema(64).parse(privateKey)
const secretKey = sodium.from_hex(privateKey)
const publicKey = sodium.to_hex(secretKey.slice(32, 64))
const manifest = await signManifest(
sodium,
packageDir,
ignoreFiles,
ignorePatterns,
secretKey
)
const $schema = V1_SCHEMA_URL
const timestamp = input.timestamp.toISOString()
const timestamp = timestampDate.toISOString()
const signature = multipartSignature(
sodium,
secretKey,
Expand Down

0 comments on commit bf523f4

Please sign in to comment.