mirror of
https://github.com/documenso/documenso.git
synced 2025-11-23 13:11:32 +10:00
80 lines
2.5 KiB
TypeScript
80 lines
2.5 KiB
TypeScript
import fs from 'node:fs';
|
|
|
|
import { env } from '@documenso/lib/utils/env';
|
|
import { signWithGCloud } from '@documenso/pdf-sign';
|
|
|
|
import { addSigningPlaceholder } from '../helpers/add-signing-placeholder';
|
|
import { updateSigningPlaceholder } from '../helpers/update-signing-placeholder';
|
|
|
|
export type SignWithGoogleCloudHSMOptions = {
|
|
pdf: Buffer;
|
|
};
|
|
|
|
export const signWithGoogleCloudHSM = async ({ pdf }: SignWithGoogleCloudHSMOptions) => {
|
|
const keyPath = env('NEXT_PRIVATE_SIGNING_GCLOUD_HSM_KEY_PATH');
|
|
|
|
if (!keyPath) {
|
|
throw new Error('No certificate path provided for Google Cloud HSM signing');
|
|
}
|
|
|
|
const googleApplicationCredentials = env('GOOGLE_APPLICATION_CREDENTIALS');
|
|
const googleApplicationCredentialsContents = env(
|
|
'NEXT_PRIVATE_SIGNING_GCLOUD_APPLICATION_CREDENTIALS_CONTENTS',
|
|
);
|
|
|
|
// To handle hosting in serverless environments like Vercel we can supply the base64 encoded
|
|
// application credentials as an environment variable and write it to a file if it doesn't exist
|
|
if (googleApplicationCredentials && googleApplicationCredentialsContents) {
|
|
if (!fs.existsSync(googleApplicationCredentials)) {
|
|
const contents = new Uint8Array(Buffer.from(googleApplicationCredentialsContents, 'base64'));
|
|
|
|
fs.writeFileSync(googleApplicationCredentials, contents);
|
|
}
|
|
}
|
|
|
|
const { pdf: pdfWithPlaceholder, byteRange } = updateSigningPlaceholder({
|
|
pdf: await addSigningPlaceholder({ pdf }),
|
|
});
|
|
|
|
const pdfWithoutSignature = Buffer.concat([
|
|
new Uint8Array(pdfWithPlaceholder.subarray(0, byteRange[1])),
|
|
new Uint8Array(pdfWithPlaceholder.subarray(byteRange[2])),
|
|
]);
|
|
|
|
const signatureLength = byteRange[2] - byteRange[1];
|
|
|
|
let cert: Buffer | null = null;
|
|
|
|
const googleCloudHsmPublicCrtFileContents = env(
|
|
'NEXT_PRIVATE_SIGNING_GCLOUD_HSM_PUBLIC_CRT_FILE_CONTENTS',
|
|
);
|
|
|
|
if (googleCloudHsmPublicCrtFileContents) {
|
|
cert = Buffer.from(googleCloudHsmPublicCrtFileContents, 'base64');
|
|
}
|
|
|
|
if (!cert) {
|
|
cert = Buffer.from(
|
|
fs.readFileSync(
|
|
env('NEXT_PRIVATE_SIGNING_GCLOUD_HSM_PUBLIC_CRT_FILE_PATH') || './example/cert.crt',
|
|
),
|
|
);
|
|
}
|
|
|
|
const signature = signWithGCloud({
|
|
keyPath,
|
|
cert,
|
|
content: pdfWithoutSignature,
|
|
});
|
|
|
|
const signatureAsHex = signature.toString('hex');
|
|
|
|
const signedPdf = Buffer.concat([
|
|
new Uint8Array(pdfWithPlaceholder.subarray(0, byteRange[1])),
|
|
new Uint8Array(Buffer.from(`<${signatureAsHex.padEnd(signatureLength - 2, '0')}>`)),
|
|
new Uint8Array(pdfWithPlaceholder.subarray(byteRange[2])),
|
|
]);
|
|
|
|
return signedPdf;
|
|
};
|