@neo4j/code-signer
Advanced tools
Comparing version 1.0.6 to 1.1.0
@@ -19,6 +19,11 @@ #!/usr/bin/env node | ||
const args = parseArgs(process.argv); | ||
const skipRevocationCheck = !!args['skip-revocation-check']; | ||
try { | ||
if (args.verify) { | ||
const rootCert = args['root-cert'] ? fs.readFileSync(args['root-cert'], 'utf8') : undefined; | ||
const result = yield _1.verifyApp(args.app, rootCert); | ||
const result = yield _1.verifyApp({ | ||
appPath: args.app, | ||
rootCertificatePem: rootCert, | ||
checkRevocationStatus: !skipRevocationCheck | ||
}); | ||
console.dir(result); | ||
@@ -25,0 +30,0 @@ if (result.status === 'UNSIGNED') { |
export declare const DIGEST_ALGORITHM_OID: string; | ||
export declare const SIGNATURE_FILENAME = "signature.pem"; | ||
export declare const CERTIFICATION_SERVER_PUBLIC_KEY = "\n-----BEGIN CERTIFICATE-----\nMIIFdjCCA16gAwIBAgICEAYwDQYJKoZIhvcNAQELBQAwbDELMAkGA1UEBhMCU0Ux\nDzANBgNVBAgMBlN3ZWRlbjETMBEGA1UECgwKTmVvNGogSW5jLjERMA8GA1UECwwI\nRGV2VG9vbHMxJDAiBgNVBAMMG05lbzRqIERldlRvb2xzIEludGVybWVkaWF0ZTAe\nFw0yMDAzMDYxNTI1MzRaFw0zMDAzMDQxNTI1MzRaMIGCMQswCQYDVQQGEwJTRTEP\nMA0GA1UECAwGU3dlZGVuMRMwEQYDVQQKDApOZW80aiBJbmMuMSIwIAYDVQQLDBlO\nZW80aiBWZXJpZmljYXRpb24gU2VydmVyMSkwJwYDVQQDDCBOZW80aiBWZXJpZmlj\nYXRpb24gU2VydmVyIFZlbmRvcjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC\nggEBAL+qPcPnr3l2U0juL3zi+EgUALCDSvP1Zcd8FpIHM/m5bUj8nObvEkbfNaz6\nANoHQZvIj1SYFqavNAGCKNxtxPyiB/9U1xQj4GRDh9dTve6fZD+D+QcBL3n8bCCq\nO8T1j20vU8NR6yYlxkTtaiPKzFzQnyB2PtiFgaDiUFzeog4Sh4UGRBO3ivPrBc5t\npSJgimlx81ftGSAQeRME6WH/Yci5qDT/OkGa0rNR5MjGTI/Z4faE21P32zqXHnAM\nRJYA7hni6HawKxyRTjkWffVXZPjOjw1Ydrrn6eBPhDNcDXUaTq5Oe3oqkaTjyxmU\ntZbMxnNVo08cnOZxWrI2fPhhXvECAwEAAaOCAQkwggEFMAkGA1UdEwQCMAAwEQYJ\nYIZIAYb4QgEBBAQDAgWgMDMGCWCGSAGG+EIBDQQmFiRPcGVuU1NMIEdlbmVyYXRl\nZCBDbGllbnQgQ2VydGlmaWNhdGUwHQYDVR0OBBYEFA4ijYt/+qCZh978EpDBDQEs\nk9lSMB8GA1UdIwQYMBaAFCGaMCJI4diXPtBIle77LZf8lYFWMA4GA1UdDwEB/wQE\nAwIF4DAdBgNVHSUEFjAUBggrBgEFBQcDAgYIKwYBBQUHAwQwQQYDVR0fBDowODA2\noDSgMoYwaHR0cHM6Ly90cnVzdC5uZW80ai5jb20vY3JsL2ludGVybWVkaWF0ZS5j\ncmwucGVtMA0GCSqGSIb3DQEBCwUAA4ICAQBDxEFXRGMUjyuZsGEtWOAMXp+tRWTg\nxE2Ij34j+EErXsK+brb9bTlo/HE9x5MwmxjFFv+IIfmPKdumqJSqSNW9XhTlYwaP\npr/LEsUy05Xl6EoouupxIDOwQ/zGHTqE5wcYsI7ONcWjeHRzrM7YwOvwTH0vuBIM\ng+Q/WFaEs8jtcJo9Pk0Zj1o88UP4V77LpVR45QLk0A2v2pM+/09ksueHokoXxHPv\nuF4TdviytJCiXRo3P0HlYibqdbfnaU0bylV74koce2GGQnOXaUCCaUjuRoktiv1C\nYWf/1NxaRJqYhHOUn9SMm7Gtj8B3KtULlkB0xO/4Iur/AxY7zXx6JOC7NEcyuN+F\nvcmjiwXyHe2IT88LVHXIf7wbBLRJFERX4FfWYavVNmXFCkOosM4LCtFWKmlDDGfI\nXqiXN+ZdasNOPeY84wtuFh4Ha1Dcjp2MAzsbuL5UvgjRi1v/rKRUOeQFBTnU3LcX\n5GDMQHtqSFg8D1OB3qwtwKmxlGmdQIAnCP41llPdpTMKYICiQfuE9ov1MSvpTJr0\nMOuM2HO7gwh6IYHDdsQJEJ4ERgsGmHvKb9glGWdMzSmPWxCYzzmsFf362HccpvCm\nwYrymyQKGV/SS3MRbFX4ehEpjQ9OHqcYqT3phQ5Uh1xjO3aehFMluhcEf9W43dAj\nYNjb4rxlaHBTLg==\n-----END CERTIFICATE-----\n"; | ||
export declare const CERTIFICATION_SERVER_URL = "https://trust.neo4j.com/api/v1/verify/app/signature"; |
@@ -6,1 +6,36 @@ "use strict"; | ||
exports.SIGNATURE_FILENAME = 'signature.pem'; | ||
exports.CERTIFICATION_SERVER_PUBLIC_KEY = ` | ||
-----BEGIN CERTIFICATE----- | ||
MIIFdjCCA16gAwIBAgICEAYwDQYJKoZIhvcNAQELBQAwbDELMAkGA1UEBhMCU0Ux | ||
DzANBgNVBAgMBlN3ZWRlbjETMBEGA1UECgwKTmVvNGogSW5jLjERMA8GA1UECwwI | ||
RGV2VG9vbHMxJDAiBgNVBAMMG05lbzRqIERldlRvb2xzIEludGVybWVkaWF0ZTAe | ||
Fw0yMDAzMDYxNTI1MzRaFw0zMDAzMDQxNTI1MzRaMIGCMQswCQYDVQQGEwJTRTEP | ||
MA0GA1UECAwGU3dlZGVuMRMwEQYDVQQKDApOZW80aiBJbmMuMSIwIAYDVQQLDBlO | ||
ZW80aiBWZXJpZmljYXRpb24gU2VydmVyMSkwJwYDVQQDDCBOZW80aiBWZXJpZmlj | ||
YXRpb24gU2VydmVyIFZlbmRvcjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC | ||
ggEBAL+qPcPnr3l2U0juL3zi+EgUALCDSvP1Zcd8FpIHM/m5bUj8nObvEkbfNaz6 | ||
ANoHQZvIj1SYFqavNAGCKNxtxPyiB/9U1xQj4GRDh9dTve6fZD+D+QcBL3n8bCCq | ||
O8T1j20vU8NR6yYlxkTtaiPKzFzQnyB2PtiFgaDiUFzeog4Sh4UGRBO3ivPrBc5t | ||
pSJgimlx81ftGSAQeRME6WH/Yci5qDT/OkGa0rNR5MjGTI/Z4faE21P32zqXHnAM | ||
RJYA7hni6HawKxyRTjkWffVXZPjOjw1Ydrrn6eBPhDNcDXUaTq5Oe3oqkaTjyxmU | ||
tZbMxnNVo08cnOZxWrI2fPhhXvECAwEAAaOCAQkwggEFMAkGA1UdEwQCMAAwEQYJ | ||
YIZIAYb4QgEBBAQDAgWgMDMGCWCGSAGG+EIBDQQmFiRPcGVuU1NMIEdlbmVyYXRl | ||
ZCBDbGllbnQgQ2VydGlmaWNhdGUwHQYDVR0OBBYEFA4ijYt/+qCZh978EpDBDQEs | ||
k9lSMB8GA1UdIwQYMBaAFCGaMCJI4diXPtBIle77LZf8lYFWMA4GA1UdDwEB/wQE | ||
AwIF4DAdBgNVHSUEFjAUBggrBgEFBQcDAgYIKwYBBQUHAwQwQQYDVR0fBDowODA2 | ||
oDSgMoYwaHR0cHM6Ly90cnVzdC5uZW80ai5jb20vY3JsL2ludGVybWVkaWF0ZS5j | ||
cmwucGVtMA0GCSqGSIb3DQEBCwUAA4ICAQBDxEFXRGMUjyuZsGEtWOAMXp+tRWTg | ||
xE2Ij34j+EErXsK+brb9bTlo/HE9x5MwmxjFFv+IIfmPKdumqJSqSNW9XhTlYwaP | ||
pr/LEsUy05Xl6EoouupxIDOwQ/zGHTqE5wcYsI7ONcWjeHRzrM7YwOvwTH0vuBIM | ||
g+Q/WFaEs8jtcJo9Pk0Zj1o88UP4V77LpVR45QLk0A2v2pM+/09ksueHokoXxHPv | ||
uF4TdviytJCiXRo3P0HlYibqdbfnaU0bylV74koce2GGQnOXaUCCaUjuRoktiv1C | ||
YWf/1NxaRJqYhHOUn9SMm7Gtj8B3KtULlkB0xO/4Iur/AxY7zXx6JOC7NEcyuN+F | ||
vcmjiwXyHe2IT88LVHXIf7wbBLRJFERX4FfWYavVNmXFCkOosM4LCtFWKmlDDGfI | ||
XqiXN+ZdasNOPeY84wtuFh4Ha1Dcjp2MAzsbuL5UvgjRi1v/rKRUOeQFBTnU3LcX | ||
5GDMQHtqSFg8D1OB3qwtwKmxlGmdQIAnCP41llPdpTMKYICiQfuE9ov1MSvpTJr0 | ||
MOuM2HO7gwh6IYHDdsQJEJ4ERgsGmHvKb9glGWdMzSmPWxCYzzmsFf362HccpvCm | ||
wYrymyQKGV/SS3MRbFX4ehEpjQ9OHqcYqT3phQ5Uh1xjO3aehFMluhcEf9W43dAj | ||
YNjb4rxlaHBTLg== | ||
-----END CERTIFICATE----- | ||
`; | ||
exports.CERTIFICATION_SERVER_URL = 'https://trust.neo4j.com/api/v1/verify/app/signature'; |
@@ -1,4 +0,4 @@ | ||
import { VerifyAppResult } from './types'; | ||
import { VerifyAppResult, VerifyAppPayload } from './types'; | ||
export * from './types'; | ||
export declare const signApp: (appPath: string, certPath: string, keyPath: string, passphrase?: string | undefined) => Promise<void>; | ||
export declare const verifyApp: (appPath: string, rootCertificatePem?: string | undefined) => Promise<VerifyAppResult>; | ||
export declare const verifyApp: (payload: VerifyAppPayload) => Promise<VerifyAppResult>; |
@@ -19,3 +19,2 @@ "use strict"; | ||
const sign_1 = require("./sign"); | ||
const types_1 = require("./types"); | ||
const verify_1 = require("./verify"); | ||
@@ -34,7 +33,9 @@ __export(require("./types")); | ||
}); | ||
exports.verifyApp = (appPath, rootCertificatePem) => __awaiter(this, void 0, void 0, function* () { | ||
exports.verifyApp = (payload) => __awaiter(this, void 0, void 0, function* () { | ||
const { appPath, rootCertificatePem, checkRevocationStatus } = payload; | ||
const signaturePath = path.join(appPath, constants_1.SIGNATURE_FILENAME); | ||
if (!fs.existsSync(signaturePath)) { | ||
return { | ||
status: 'UNSIGNED' | ||
status: 'UNSIGNED', | ||
revocationStatus: 'OK' | ||
}; | ||
@@ -44,13 +45,17 @@ } | ||
const signaturePem = fs.readFileSync(signaturePath, 'utf8'); | ||
const result = verify_1.verify({ | ||
const result = yield verify_1.verify({ | ||
data: digest, | ||
rootCertificatePem, | ||
signaturePem | ||
signaturePem, | ||
checkRevocationStatus | ||
}); | ||
if (!result.isValid) { | ||
return Promise.reject(new types_1.InvalidSignatureError(result.error)); | ||
return Promise.reject(result.error); | ||
} | ||
const status = result.isTrusted ? 'TRUSTED' : 'UNTRUSTED'; | ||
const revocationStatus = typeof result['isRevoked'] === 'undefined' ? 'UNKNOWN' : result.isRevoked ? 'REVOKED' : 'OK'; | ||
return { | ||
status, | ||
revocationError: result.revocationError, | ||
revocationStatus, | ||
signature: signaturePem, | ||
@@ -57,0 +62,0 @@ certificate: result.certificate |
import { pki } from 'node-forge'; | ||
export declare type SignatureStatus = 'TRUSTED' | 'UNSIGNED' | 'UNTRUSTED'; | ||
export declare type RevokationStatus = 'OK' | 'REVOKED' | 'UNKNOWN'; | ||
export interface VerifyAppPayload { | ||
appPath: string; | ||
rootCertificatePem?: string; | ||
checkRevocationStatus: boolean; | ||
} | ||
export interface VerifyAppResult { | ||
status: SignatureStatus; | ||
revocationStatus: RevokationStatus; | ||
certificate?: CertificateInfo; | ||
signature?: string; | ||
revocationError?: string; | ||
} | ||
@@ -15,2 +23,3 @@ export declare class InvalidSignatureError extends Error { | ||
rootCertificatePem?: string; | ||
checkRevocationStatus: boolean; | ||
} | ||
@@ -20,2 +29,4 @@ export interface VerifyResult { | ||
isTrusted: boolean; | ||
isRevoked?: boolean; | ||
revocationError?: string; | ||
error?: any; | ||
@@ -22,0 +33,0 @@ certificate?: CertificateInfo; |
import { pki } from 'node-forge'; | ||
import { VerifyCertResult, VerifyOptions, VerifyResult, VerifySignatureResult } from './types'; | ||
export declare const verify: (options: VerifyOptions) => VerifyResult; | ||
export declare const verify: (options: VerifyOptions) => Promise<VerifyResult>; | ||
export declare const verifyCertificate: (certificate: string | pki.Certificate, caPem?: string | undefined) => VerifyCertResult; | ||
export declare function verifyCertificateNotRevoked(signaturePem: string): Promise<{ | ||
revocationError?: string; | ||
isRevoked: boolean; | ||
}>; | ||
export declare const verifySignature: (signaturePem: string, data: string) => VerifySignatureResult; |
"use strict"; | ||
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { | ||
return new (P || (P = Promise))(function (resolve, reject) { | ||
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } | ||
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } | ||
function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); } | ||
step((generator = generator.apply(thisArg, _arguments || [])).next()); | ||
}); | ||
}; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
const node_forge_1 = require("node-forge"); | ||
const crypto = require("crypto"); | ||
const node_fetch_1 = require("node-fetch"); | ||
const certificate_1 = require("./certificate"); | ||
const constants_1 = require("./constants"); | ||
exports.verify = (options) => { | ||
const types_1 = require("./types"); | ||
exports.verify = (options) => __awaiter(this, void 0, void 0, function* () { | ||
const { data, signaturePem, rootCertificatePem } = options; | ||
@@ -12,2 +23,5 @@ let isValid = false; | ||
let certificate; | ||
const { revocationError, isRevoked } = options.checkRevocationStatus | ||
? yield verifyCertificateNotRevoked(signaturePem) | ||
: { revocationError: undefined, isRevoked: undefined }; | ||
try { | ||
@@ -24,5 +38,7 @@ ({ certificate } = exports.verifySignature(signaturePem, data)); | ||
isTrusted, | ||
isValid | ||
isValid, | ||
revocationError, | ||
isRevoked | ||
}; | ||
}; | ||
}); | ||
exports.verifyCertificate = (certificate, caPem) => { | ||
@@ -47,3 +63,3 @@ const cert = typeof certificate === 'string' ? node_forge_1.pki.certificateFromPem(certificate) : certificate; | ||
else { | ||
error = isCertError(e) ? e.message : e; | ||
error = isCertError(e) ? new types_1.InvalidSignatureError(e.message) : e; | ||
} | ||
@@ -57,2 +73,27 @@ } | ||
}; | ||
function verifyCertificateNotRevoked(signaturePem) { | ||
const prepped = crypto.createPublicKey({ | ||
key: constants_1.CERTIFICATION_SERVER_PUBLIC_KEY | ||
}); | ||
const rand = `${Math.random() * 1000}`; | ||
const verify = crypto.createVerify('RSA-SHA512'); | ||
verify.update(rand); | ||
return node_fetch_1.default(constants_1.CERTIFICATION_SERVER_URL, { | ||
method: 'POST', | ||
headers: { | ||
'X-Request-ID': rand, | ||
'Content-Type': 'text/html' | ||
}, | ||
body: signaturePem | ||
}) | ||
.then(res => res.text()) | ||
.then(res => ({ | ||
isRevoked: !verify.verify(prepped, res, 'base64') | ||
})) | ||
.catch(({ message: revocationError }) => ({ | ||
revocationError, | ||
isRevoked: false | ||
})); | ||
} | ||
exports.verifyCertificateNotRevoked = verifyCertificateNotRevoked; | ||
function verifyUntrustedCert(cert) { | ||
@@ -59,0 +100,0 @@ let error; |
{ | ||
"name": "@neo4j/code-signer", | ||
"version": "1.0.6", | ||
"version": "1.1.0", | ||
"description": "A CLI tool for signing code", | ||
@@ -24,2 +24,3 @@ "main": "lib/index.js", | ||
"minimist": "1.2.0", | ||
"node-fetch": "^2.6.0", | ||
"node-forge": "0.7.6", | ||
@@ -31,3 +32,4 @@ "p-limit": "2.1.0" | ||
"@types/jest": "23.3.12", | ||
"@types/node": "10.12.18", | ||
"@types/node": "12.12.17", | ||
"@types/node-fetch": "^2.5.4", | ||
"@types/tempy": "0.2.0", | ||
@@ -34,0 +36,0 @@ "fs-extra": "7.0.1", |
# Code Signer | ||
A CLI tool for signing code used by Neo4j Graph platform. | ||
Creates a `signature.pem` file in the signed folder. | ||
Creates a `signature.pem` file in the signed folder. | ||
If verifies signatures locally and against Neo4j:s CRL server | ||
for revoked certificates when online. | ||
@@ -28,3 +30,6 @@ ## Usage | ||
You can also pass the `--skip-revocation-check` flag to skip the certificate revocation check against Neo4j:s CRL server. | ||
## Common usage pattern | ||
These steps are usually what's needed to sign a node application. | ||
@@ -47,3 +52,3 @@ | ||
--passphrase your-private-key-passphrase | ||
# pack app again, from inside package/ folder. Important! | ||
@@ -61,4 +66,4 @@ cd package | ||
- Build: `yarn build` | ||
- Test: `yarn test` | ||
- Package: `yarn pack` | ||
- Build: `yarn build` | ||
- Test: `yarn test` | ||
- Package: `yarn pack` |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
49756
804
67
9
10
+ Addednode-fetch@^2.6.0
+ Addednode-fetch@2.7.0(transitive)
+ Addedtr46@0.0.3(transitive)
+ Addedwebidl-conversions@3.0.1(transitive)
+ Addedwhatwg-url@5.0.0(transitive)