Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Jarred/bun #201

Open
wants to merge 65 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
65 commits
Select commit Hold shift + click to select a range
6ef6d34
BoringSSL also needs sni_tree.cpp
Jarred-Sumner Oct 17, 2022
77a0331
Add a way to change the memory allocator
Jarred-Sumner Jul 4, 2022
cec61c6
Set a timeout for kqueue
Jarred-Sumner Jul 4, 2022
2788654
Update libusockets.h
Jarred-Sumner Jul 4, 2022
60c94ba
Use machports on macOS instead of EVFILT_USER
Jarred-Sumner Sep 22, 2022
c16e5be
Support 3rd-party events added to kqueue
Jarred-Sumner Sep 22, 2022
e481749
Support detaching & attaching sockets
Jarred-Sumner Sep 22, 2022
4ba4e0a
Fix how we do ticking
Jarred-Sumner Sep 29, 2022
506c240
Optimization: don't call kqueue_change on close
Jarred-Sumner Sep 30, 2022
c8bd0dd
explicit alignment
Jarred-Sumner Oct 18, 2022
0b2fd09
Linux merge issue
Jarred-Sumner Oct 18, 2022
ca30fba
Build fixes for Clang 15
Jarred-Sumner Dec 27, 2022
af2731d
Use `connectx`
Jarred-Sumner Dec 27, 2022
f580aa0
linux build fix
Jarred-Sumner Dec 27, 2022
48ffeb1
Create .gitignore
Jarred-Sumner Jan 8, 2023
fafc241
connectx causes issues
Jarred-Sumner Jan 8, 2023
6d8455b
Merge remote-tracking branch 'upstream' into jarred/bun
Jarred-Sumner Jan 13, 2023
e72ca47
Update libusockets.h
Jarred-Sumner Jan 13, 2023
a6d0daa
Handle when there's data left in the buffer
Jarred-Sumner Jan 17, 2023
f17a4da
add key and cert content options
cirospaciari Mar 13, 2023
d532205
add multiple certs, keys and cas capabilities
cirospaciari Mar 17, 2023
ea8e0ba
update example
cirospaciari Mar 17, 2023
70f3f2b
SSL_VERIFY_PEER on CA
cirospaciari Mar 17, 2023
2141c83
add secure options
cirospaciari Mar 17, 2023
7d04a09
re-add reject and request_cert
cirospaciari Mar 17, 2023
e1e4a52
add verify error
cirospaciari Mar 17, 2023
19bdf31
pending cert cb to use verify_error
cirospaciari Mar 17, 2023
f28a75d
handshake progress
cirospaciari Mar 22, 2023
0017031
start client and server at different stages
cirospaciari Mar 22, 2023
475db01
pass context instead of socket on handshake handler
cirospaciari Mar 22, 2023
f2e84b4
handshake now workds
cirospaciari Mar 22, 2023
8881571
allow read/write properly
cirospaciari Mar 22, 2023
59e9a57
update openssl
cirospaciari Mar 24, 2023
2d31285
wait client be able to send handshake
cirospaciari Mar 24, 2023
63f1ead
fix handshaking
cirospaciari Mar 24, 2023
9d3a1f1
avoid segfault when closing socket in handshake reject
cirospaciari Mar 26, 2023
f1cd330
change handshake logic
cirospaciari Mar 27, 2023
a9d8070
fix Connection: Close when using SSL
cirospaciari Mar 27, 2023
0e05a07
remove log
cirospaciari Mar 27, 2023
e253c91
rename aux functions to be more follow usockets name spec
cirospaciari Mar 27, 2023
33c50d1
Merge pull request #1 from cirospaciari/ciro/bun
Jarred-Sumner Mar 28, 2023
ac8b68e
fix init for ssl_data
cirospaciari Apr 5, 2023
99d36a4
Merge pull request #2 from cirospaciari/ciro/fix-ssl-data-init
Jarred-Sumner Apr 5, 2023
a5f4b6a
add root_certs
cirospaciari May 18, 2023
c18b3c8
remove unused prints
cirospaciari May 18, 2023
397ee3c
add scripts to generate root certs
cirospaciari May 18, 2023
c8ed7c8
fix naming in scripts generation
cirospaciari May 18, 2023
5439add
fix init_root_certs
cirospaciari May 18, 2023
c5a7a82
update comment
cirospaciari May 18, 2023
a2c9d2a
Merge pull request #4 from cirospaciari/ciro/feat-root-certs
Jarred-Sumner May 18, 2023
9581630
root certs only when requested
cirospaciari May 19, 2023
dc9c823
Merge pull request #5 from cirospaciari/ciro/fix-root-certs-only-when…
Jarred-Sumner May 19, 2023
c236efd
add tls wrap compatibility
cirospaciari Jun 29, 2023
8f02063
oops
cirospaciari Jun 29, 2023
e774f8d
Merge pull request #6 from cirospaciari/ciro/tls-wrap
Jarred-Sumner Jun 29, 2023
bc8f85a
update root certs and expose them via API
cirospaciari Jul 19, 2023
79840d0
Merge pull request #7 from cirospaciari/ciro/update-and-expose-root-c…
Jarred-Sumner Jul 19, 2023
44e3a73
fix type mistmatch
cirospaciari Jul 19, 2023
fb285d1
Merge pull request #8 from cirospaciari/ciro/update-and-expose-root-c…
Jarred-Sumner Jul 19, 2023
f82de26
add len on root certs
cirospaciari Jul 19, 2023
afab9cf
Merge pull request #9 from cirospaciari/ciro/update-and-expose-root-c…
Jarred-Sumner Jul 19, 2023
6ab988e
Fixes bug with localhost
Jarred-Sumner Jul 23, 2023
9974af3
Try all addresses instead of only the first one
Jarred-Sumner Jul 23, 2023
4ca9ca2
fix and update
cirospaciari Jul 28, 2023
9e02a27
Merge pull request #10 from cirospaciari/ciro/fix-root-cert-len
Jarred-Sumner Jul 28, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
*.i
*.o
*.s
*.bc
*.ii
2 changes: 1 addition & 1 deletion boringssl
Submodule boringssl updated 673 files
24,518 changes: 24,518 additions & 0 deletions certdata.txt

Large diffs are not rendered by default.

32 changes: 22 additions & 10 deletions examples/http_server.c
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ struct us_socket_t *on_http_socket_writable(struct us_socket_t *s) {
}

struct us_socket_t *on_http_socket_close(struct us_socket_t *s, int code, void *reason) {
printf("Client disconnected\n");
// printf("Client disconnected\n");

return s;
}
Expand Down Expand Up @@ -77,7 +77,8 @@ struct us_socket_t *on_http_socket_open(struct us_socket_t *s, int is_client, ch
/* Timeout idle HTTP connections */
us_socket_timeout(SSL, s, 30);

printf("Client connected\n");

// printf("Client connected\n");

return s;
}
Expand All @@ -92,12 +93,23 @@ int main() {
struct us_loop_t *loop = us_create_loop(0, on_wakeup, on_pre, on_post, 0);

/* Create a socket context for HTTP */
struct us_socket_context_options_t options = {};
options.key_file_name = "../../misc/key.pem";
options.cert_file_name = "../../misc/cert.pem";
struct us_bun_socket_context_options_t options = {};
const char* certs[] = {
"-----BEGIN CERTIFICATE-----\nMIIDXTCCAkWgAwIBAgIJAKLdQVPy90jjMA0GCSqGSIb3DQEBCwUAMEUxCzAJBgNV\nBAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRlcm5ldCBX\naWRnaXRzIFB0eSBMdGQwHhcNMTkwMjAzMTQ0OTM1WhcNMjAwMjAzMTQ0OTM1WjBF\nMQswCQYDVQQGEwJBVTETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50\nZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB\nCgKCAQEA7i7IIEdICTiSTVx+ma6xHxOtcbd6wGW3nkxlCkJ1UuV8NmY5ovMsGnGD\nhJJtUQ2j5ig5BcJUf3tezqCNW4tKnSOgSISfEAKvpn2BPvaFq3yx2Yjz0ruvcGKp\nDMZBXmB/AAtGyN/UFXzkrcfppmLHJTaBYGG6KnmU43gPkSDy4iw46CJFUOupc51A\nFIz7RsE7mbT1plCM8e75gfqaZSn2k+Wmy+8n1HGyYHhVISRVvPqkS7gVLSVEdTea\nUtKP1Vx/818/HDWk3oIvDVWI9CFH73elNxBkMH5zArSNIBTehdnehyAevjY4RaC/\nkK8rslO3e4EtJ9SnA4swOjCiqAIQEwIDAQABo1AwTjAdBgNVHQ4EFgQUv5rc9Smm\n9c4YnNf3hR49t4rH4yswHwYDVR0jBBgwFoAUv5rc9Smm9c4YnNf3hR49t4rH4ysw\nDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEATcL9CAAXg0u//eYUAlQa\nL+l8yKHS1rsq1sdmx7pvsmfZ2g8ONQGfSF3TkzkI2OOnCBokeqAYuyT8awfdNUtE\nEHOihv4ZzhK2YZVuy0fHX2d4cCFeQpdxno7aN6B37qtsLIRZxkD8PU60Dfu9ea5F\nDDynnD0TUabna6a0iGn77yD8GPhjaJMOz3gMYjQFqsKL252isDVHEDbpVxIzxPmN\nw1+WK8zRNdunAcHikeoKCuAPvlZ83gDQHp07dYdbuZvHwGj0nfxBLc9qt90XsBtC\n4IYR7c/bcLMmKXYf0qoQ4OzngsnPI5M+v9QEHvYWaKVwFY4CTcSNJEwfXw+BAeO5\nOA==\n-----END CERTIFICATE-----"};
options.cert = &(certs[0]);
options.cert_count = 1;
const char* keys[] = { "-----BEGIN PRIVATE KEY-----\nMIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDuLsggR0gJOJJN\nXH6ZrrEfE61xt3rAZbeeTGUKQnVS5Xw2Zjmi8ywacYOEkm1RDaPmKDkFwlR/e17O\noI1bi0qdI6BIhJ8QAq+mfYE+9oWrfLHZiPPSu69wYqkMxkFeYH8AC0bI39QVfOSt\nx+mmYsclNoFgYboqeZTjeA+RIPLiLDjoIkVQ66lznUAUjPtGwTuZtPWmUIzx7vmB\n+pplKfaT5abL7yfUcbJgeFUhJFW8+qRLuBUtJUR1N5pS0o/VXH/zXz8cNaTegi8N\nVYj0IUfvd6U3EGQwfnMCtI0gFN6F2d6HIB6+NjhFoL+QryuyU7d7gS0n1KcDizA6\nMKKoAhATAgMBAAECggEAd5g/3o1MK20fcP7PhsVDpHIR9faGCVNJto9vcI5cMMqP\n6xS7PgnSDFkRC6EmiLtLn8Z0k2K3YOeGfEP7lorDZVG9KoyE/doLbpK4MfBAwBG1\nj6AHpbmd5tVzQrnNmuDjBBelbDmPWVbD0EqAFI6mphXPMqD/hFJWIz1mu52Kt2s6\n++MkdqLO0ORDNhKmzu6SADQEcJ9Suhcmv8nccMmwCsIQAUrfg3qOyqU4//8QB8ZM\njosO3gMUesihVeuF5XpptFjrAliPgw9uIG0aQkhVbf/17qy0XRi8dkqXj3efxEDp\n1LSqZjBFiqJlFchbz19clwavMF/FhxHpKIhhmkkRSQKBgQD9blaWSg/2AGNhRfpX\nYq+6yKUkUD4jL7pmX1BVca6dXqILWtHl2afWeUorgv2QaK1/MJDH9Gz9Gu58hJb3\nymdeAISwPyHp8euyLIfiXSAi+ibKXkxkl1KQSweBM2oucnLsNne6Iv6QmXPpXtro\nnTMoGQDS7HVRy1on5NQLMPbUBQKBgQDwmN+um8F3CW6ZV1ZljJm7BFAgNyJ7m/5Q\nYUcOO5rFbNsHexStrx/h8jYnpdpIVlxACjh1xIyJ3lOCSAWfBWCS6KpgeO1Y484k\nEYhGjoUsKNQia8UWVt+uWnwjVSDhQjy5/pSH9xyFrUfDg8JnSlhsy0oC0C/PBjxn\nhxmADSLnNwKBgQD2A51USVMTKC9Q50BsgeU6+bmt9aNMPvHAnPf76d5q78l4IlKt\nwMs33QgOExuYirUZSgjRwknmrbUi9QckRbxwOSqVeMOwOWLm1GmYaXRf39u2CTI5\nV9gTMHJ5jnKd4gYDnaA99eiOcBhgS+9PbgKSAyuUlWwR2ciL/4uDzaVeDQKBgDym\nvRSeTRn99bSQMMZuuD5N6wkD/RxeCbEnpKrw2aZVN63eGCtkj0v9LCu4gptjseOu\n7+a4Qplqw3B/SXN5/otqPbEOKv8Shl/PT6RBv06PiFKZClkEU2T3iH27sws2EGru\nw3C3GaiVMxcVewdg1YOvh5vH8ZVlxApxIzuFlDvnAoGAN5w+gukxd5QnP/7hcLDZ\nF+vesAykJX71AuqFXB4Wh/qFY92CSm7ImexWA/L9z461+NKeJwb64Nc53z59oA10\n/3o2OcIe44kddZXQVP6KTZBd7ySVhbtOiK3/pCy+BQRsrC7d71W914DxNWadwZ+a\njtwwKjDzmPwdIXDSQarCx0U=\n-----END PRIVATE KEY-----" };
options.key = &(keys[0]);
options.key_count = 1;
// options.cert_file_name = "./misc/cert.pem";
// options.key_file_name = "./misc/key.pem";
options.passphrase = "1234";
const char* cas[] = { "-----BEGIN CERTIFICATE-----\nMIIDAzCCAesCFHwXVn+q3YnlwmwijComXUB9sTt0MA0GCSqGSIb3DQEBCwUAMDwx\nFDASBgNVBAoMC3VOZXR3b3JraW5nMREwDwYDVQQKDAh1U29ja2V0czERMA8GA1UE\nAwwIdmFsaWRfY2EwHhcNMjMwMzEzMTQxNjM2WhcNMjQwMzEyMTQxNjM2WjBAMRQw\nEgYDVQQKDAt1TmV0d29ya2luZzERMA8GA1UECgwIdVNvY2tldHMxFTATBgNVBAMM\nDHZhbGlkX2NsaWVudDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANPH\nSp1VaI2kTmBprubniSG8j2uu88u5MZxC5Xkv4DMEu0lhWrg9zk07daK2MNeCdZKI\nT4pIgeKxNXSd3KZK9lJxUBMoTuAhvoribJOsz7Z9nF9enSSuhY2Z529tTiftFpYh\n8NcQIame6fykOy1uU7SnPUkq8cXoOmr0/bPs9Kdsb/aAWf8gOt41cKqllmBpMzQJ\nZR5y2DZenQuTG0GUSrQ3kKopOayXATm5gNRf8gGKPsRqo6DwNhbNXYKL/hG/nqDT\nBUNU0aSnFch7HMpAaJ1sY/TAMmkMKMvL40RE0jsm8bf4ah0imAHjG4gBSdZz7oHi\nwQHsEwI53BAcf8XIrxUCAwEAATANBgkqhkiG9w0BAQsFAAOCAQEAJHNXWrCgdp0v\njMPFT1Tgs5Jwbp6E+oh4GzcMXCKBT+34r9MymN5h627LbPZ6G7VMZ0TsKsSKMVkz\n44xHclyQZOxRww4Lq3csB03yuYHdQkxAh99+JsU9LwtJiAy8H2aqG/CcgqIHMZjd\nXSBkk28dTLyE9Xfc71K0bVcRNISzyGEDdbcei6MCVi4NdK0Df3R5yKpUQ+2BZ400\ne9gRFLOQrOaYYzZ7fKEPc3LPHzDiLmP7racaMpzL3a/rc5ovWWVKWeHXgDroYWlt\ngfrX1VvftqsuhEg1Bef0bcqjeEf2o9Abk6jKRwpPnG51rUEEfpceSxA+Zk//Taqz\nTfS53plZRQ==\n-----END CERTIFICATE-----"};
options.ca = &(cas[0]);
options.ca_count = 1;

struct us_socket_context_t *http_context = us_create_socket_context(SSL, loop, sizeof(struct http_context), options);
printf("Creating SSL context!!!\n");
struct us_socket_context_t *http_context = us_create_bun_socket_context(SSL, loop, sizeof(struct http_context), options);

if (!http_context) {
printf("Could not load SSL cert/key\n");
Expand All @@ -106,11 +118,9 @@ int main() {

/* Generate the shared response */
const char body[] = "<html><body><h1>Why hello there!</h1></body></html>";

struct http_context *http_context_ext = (struct http_context *) us_socket_context_ext(SSL, http_context);
http_context_ext->response = (char *) malloc(128 + sizeof(body) - 1);
http_context_ext->length = snprintf(http_context_ext->response, 128 + sizeof(body) - 1, "HTTP/1.1 200 OK\r\nContent-Length: %ld\r\n\r\n%s", sizeof(body) - 1, body);

/* Set up event handlers */
us_socket_context_on_open(SSL, http_context, on_http_socket_open);
us_socket_context_on_data(SSL, http_context, on_http_socket_data);
Expand All @@ -120,10 +130,12 @@ int main() {
us_socket_context_on_end(SSL, http_context, on_http_socket_end);

/* Start serving HTTP connections */
struct us_listen_socket_t *listen_socket = us_socket_context_listen(SSL, http_context, 0, 3000, 0, sizeof(struct http_socket));
struct us_listen_socket_t *listen_socket = us_socket_context_listen(SSL, http_context, 0, 8000, 0, sizeof(struct http_socket));
//int ssl, struct us_socket_context_t *context, const char *hostname_pattern, struct us_bun_socket_context_options_t options, void *user
us_bun_socket_context_add_server_name(SSL, http_context, "localhost", options, NULL);

if (listen_socket) {
printf("Listening on port 3000...\n");
printf("Listening on port 8000...\n");
us_loop_run(loop);
} else {
printf("Failed to listen!\n");
Expand Down
251 changes: 251 additions & 0 deletions generate-root-certs.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,251 @@
// Script to update certdata.txt from NSS.
import { execFileSync } from 'node:child_process';
import { randomUUID } from 'node:crypto';
import { createWriteStream } from 'node:fs';
import { basename, dirname, join, relative } from 'node:path';
import { Readable } from 'node:stream';
import { pipeline } from 'node:stream/promises';
import { fileURLToPath } from 'node:url';
import { parseArgs } from 'node:util';

// Constants for NSS release metadata.
const kNSSVersion = 'version';
const kNSSDate = 'date';
const kFirefoxVersion = 'firefoxVersion';
const kFirefoxDate = 'firefoxDate';

const __filename = fileURLToPath(import.meta.url);
const now = new Date();

const formatDate = (d) => {
const iso = d.toISOString();
return iso.substring(0, iso.indexOf('T'));
};

const getCertdataURL = (version) => {
const tag = `NSS_${version.replaceAll('.', '_')}_RTM`;
const certdataURL = `https://hg.mozilla.org/projects/nss/raw-file/${tag}/lib/ckfw/builtins/certdata.txt`;
return certdataURL;
};

const normalizeTD = (text) => {
// Remove whitespace and any HTML tags.
return text?.trim().replace(/<.*?>/g, '');
};
const getReleases = (text) => {
const releases = [];
const tableRE = /<table [^>]+>([\S\s]*?)<\/table>/g;
const tableRowRE = /<tr ?[^>]*>([\S\s]*?)<\/tr>/g;
const tableHeaderRE = /<th ?[^>]*>([\S\s]*?)<\/th>/g;
const tableDataRE = /<td ?[^>]*>([\S\s]*?)<\/td>/g;
for (const table of text.matchAll(tableRE)) {
const columns = {};
const matches = table[1].matchAll(tableRowRE);
// First row has the table header.
let row = matches.next();
if (row.done) {
continue;
}
const headers = Array.from(row.value[1].matchAll(tableHeaderRE), (m) => m[1]);
if (headers.length > 0) {
for (let i = 0; i < headers.length; i++) {
if (/NSS version/i.test(headers[i])) {
columns[kNSSVersion] = i;
} else if (/Release.*from branch/i.test(headers[i])) {
columns[kNSSDate] = i;
} else if (/Firefox version/i.test(headers[i])) {
columns[kFirefoxVersion] = i;
} else if (/Firefox release date/i.test(headers[i])) {
columns[kFirefoxDate] = i;
}
}
}
// Filter out "NSS Certificate bugs" table.
if (columns[kNSSDate] === undefined) {
continue;
}
// Scrape releases.
row = matches.next();
while (!row.done) {
const cells = Array.from(row.value[1].matchAll(tableDataRE), (m) => m[1]);
const release = {};
release[kNSSVersion] = normalizeTD(cells[columns[kNSSVersion]]);
release[kNSSDate] = new Date(normalizeTD(cells[columns[kNSSDate]]));
release[kFirefoxVersion] = normalizeTD(cells[columns[kFirefoxVersion]]);
release[kFirefoxDate] = new Date(normalizeTD(cells[columns[kFirefoxDate]]));
releases.push(release);
row = matches.next();
}
}
return releases;
};

const getLatestVersion = async (releases) => {
const arrayNumberSortDescending = (x, y, i) => {
if (x[i] === undefined && y[i] === undefined) {
return 0;
} else if (x[i] === y[i]) {
return arrayNumberSortDescending(x, y, i + 1);
}
return (y[i] ?? 0) - (x[i] ?? 0);
};
const extractVersion = (t) => {
return t[kNSSVersion].split('.').map((n) => parseInt(n));
};
const releaseSorter = (x, y) => {
return arrayNumberSortDescending(extractVersion(x), extractVersion(y), 0);
};
// Return the most recent certadata.txt that exists on the server.
const sortedReleases = releases.sort(releaseSorter).filter(pastRelease);
for (const candidate of sortedReleases) {
const candidateURL = getCertdataURL(candidate[kNSSVersion]);
if (values.verbose) {
console.log(`Trying ${candidateURL}`);
}
const response = await fetch(candidateURL, { method: 'HEAD' });
if (response.ok) {
return candidate[kNSSVersion];
}
}
};

const pastRelease = (r) => {
return r[kNSSDate] < now;
};

const options = {
help: {
type: 'boolean',
},
file: {
short: 'f',
type: 'string',
},
verbose: {
short: 'v',
type: 'boolean',
},
};
const {
positionals,
values,
} = parseArgs({
allowPositionals: true,
options,
});

if (values.help) {
console.log(`Usage: ${basename(__filename)} [OPTION]... [VERSION]...`);
console.log();
console.log('Updates certdata.txt to NSS VERSION (most recent release by default).');
console.log('');
console.log(' -f, --file=FILE writes a commit message reflecting the change to the');
console.log(' specified FILE');
console.log(' -v, --verbose writes progress to stdout');
console.log(' --help display this help and exit');
process.exit(0);
}

const scheduleURL = 'https://wiki.mozilla.org/NSS:Release_Versions';
if (values.verbose) {
console.log(`Fetching NSS release schedule from ${scheduleURL}`);
}
const schedule = await fetch(scheduleURL);
if (!schedule.ok) {
console.error(`Failed to fetch ${scheduleURL}: ${schedule.status}: ${schedule.statusText}`);
process.exit(-1);
}
const scheduleText = await schedule.text();
const nssReleases = getReleases(scheduleText);

// Retrieve metadata for the NSS release being updated to.
const version = positionals[0] ?? await getLatestVersion(nssReleases);
const release = nssReleases.find((r) => {
return new RegExp(`^${version.replace('.', '\\.')}\\b`).test(r[kNSSVersion]);
});
if (!pastRelease(release)) {
console.warn(`Warning: NSS ${version} is not due to be released until ${formatDate(release[kNSSDate])}`);
}
if (values.verbose) {
console.log('Found NSS version:');
console.log(release);
}

// Fetch certdata.txt and overwrite the local copy.
const certdataURL = getCertdataURL(version);
if (values.verbose) {
console.log(`Fetching ${certdataURL}`);
}

const checkoutDir = dirname(__filename);
const certdata = await fetch(certdataURL);
const certdataFile = join(checkoutDir, 'certdata.txt');
if (!certdata.ok) {
console.error(`Failed to fetch ${certdataURL}: ${certdata.status}: ${certdata.statusText}`);
process.exit(-1);
}
if (values.verbose) {
console.log(`Writing ${certdataFile}`);
}
await pipeline(certdata.body, createWriteStream(certdataFile));

// Run generate-root-certs.pl to generate src/crypto/root_certs.h.
if (values.verbose) {
console.log('Running generate-root-certs.pl');
}
const opts = { encoding: 'utf8' };
const mkCABundleTool = join(checkoutDir, 'generate-root-certs.pl');
const mkCABundleOut = execFileSync(mkCABundleTool,
values.verbose ? [ '-v' ] : [],
opts);
if (values.verbose) {
console.log(mkCABundleOut);
}

// Determine certificates added and/or removed.
const certHeaderFile = relative(process.cwd(), join(checkoutDir, 'src', 'crypto', 'root_certs.h'));
const diff = execFileSync('git', [ 'diff-files', '-u', '--', certHeaderFile ], opts);
if (values.verbose) {
console.log(diff);
}
const certsAddedRE = /^\+\/\* (.*) \*\//gm;
const certsRemovedRE = /^-\/\* (.*) \*\//gm;
const added = [ ...diff.matchAll(certsAddedRE) ].map((m) => m[1]);
const removed = [ ...diff.matchAll(certsRemovedRE) ].map((m) => m[1]);

const commitMsg = [
`crypto: update root certificates to NSS ${release[kNSSVersion]}`,
'',
`This is the certdata.txt[0] from NSS ${release[kNSSVersion]}, released on ${formatDate(release[kNSSDate])}.`,
'',
`This is the version of NSS that ${release[kFirefoxDate] < now ? 'shipped' : 'will ship'} in Firefox ${release[kFirefoxVersion]} on`,
`${formatDate(release[kFirefoxDate])}.`,
'',
];
if (added.length > 0) {
commitMsg.push('Certificates added:');
commitMsg.push(...added.map((cert) => `- ${cert}`));
commitMsg.push('');
}
if (removed.length > 0) {
commitMsg.push('Certificates removed:');
commitMsg.push(...removed.map((cert) => `- ${cert}`));
commitMsg.push('');
}
commitMsg.push(`[0] ${certdataURL}`);
const delimiter = randomUUID();
const properties = [
`NEW_VERSION=${release[kNSSVersion]}`,
`COMMIT_MSG<<${delimiter}`,
...commitMsg,
delimiter,
'',
].join('\n');
if (values.verbose) {
console.log(properties);
}
const propertyFile = values.file;
if (propertyFile !== undefined) {
console.log(`Writing to ${propertyFile}`);
await pipeline(Readable.from(properties), createWriteStream(propertyFile));
}
Loading