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

WARC-Protocol + WARC-Cipher-Suite headers #715

Open
wants to merge 6 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 2 commits
Commits
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
8 changes: 8 additions & 0 deletions src/util/recorder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1755,6 +1755,14 @@ function createResponse(
"WARC-Page-ID": pageid,
};

if (reqresp.protocols.length) {
warcHeaders["WARC-Protocol"] = reqresp.protocols.join(", ");
}

if (reqresp.cipher) {
warcHeaders["WARC-Cipher-Suite"] = reqresp.cipher;
}

if (reqresp.resourceType) {
warcHeaders["WARC-Resource-Type"] = reqresp.resourceType;
}
Expand Down
71 changes: 50 additions & 21 deletions src/util/reqresp.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { Protocol } from "puppeteer-core";
import { postToGetUrl } from "warcio";
import { HTML_TYPES } from "./constants.js";
import { Response } from "undici";
import { logger } from "./logger.js";
ikreymer marked this conversation as resolved.
Show resolved Hide resolved

const CONTENT_LENGTH = "content-length";
const CONTENT_RANGE = "content-range";
Expand All @@ -25,7 +26,9 @@ export class RequestResponseInfo {

method?: string;
url!: string;
protocol?: string = "HTTP/1.1";

protocols: string[] = [];
cipher?: string;

mimeType?: string;

Expand Down Expand Up @@ -132,7 +135,9 @@ export class RequestResponseInfo {

this.setStatus(response.status, response.statusText);

this.protocol = response.protocol;
if (response.protocol) {
this.protocols.push(response.protocol);
}

if (resourceType) {
this.resourceType = resourceType.toLowerCase();
Expand All @@ -153,11 +158,17 @@ export class RequestResponseInfo {

this.fromServiceWorker = !!response.fromServiceWorker;

if (response.securityDetails) {
const issuer: string = response.securityDetails.issuer || "";
const { securityDetails } = response;

if (securityDetails) {
const securityProtocol = securityDetails.protocol
.replaceAll(" ", "/")
.toLowerCase();
this.protocols.push(securityProtocol);
this.cipher = getCipher(securityDetails, securityProtocol, this.url);
const issuer: string = securityDetails.issuer || "";
const ctc: string =
response.securityDetails.certificateTransparencyCompliance ===
"compliant"
securityDetails.certificateTransparencyCompliance === "compliant"
? "1"
: "0";
this.extraOpts.cert = { issuer, ctc };
Expand Down Expand Up @@ -204,21 +215,6 @@ export class RequestResponseInfo {
this.requestHeaders = params.headers;
}

getResponseHeadersText() {
let headers = `${this.protocol} ${this.status} ${this.statusText}\r\n`;

if (this.responseHeaders) {
for (const header of Object.keys(this.responseHeaders)) {
headers += `${header}: ${this.responseHeaders[header].replace(
/\n/g,
", ",
)}\r\n`;
}
}
headers += "\r\n";
return headers;
}

hasRequest() {
return this.method && (this.requestHeaders || this.requestHeadersText);
}
Expand Down Expand Up @@ -417,3 +413,36 @@ export function isHTMLMime(mime: string) {
export function isRedirectStatus(status: number) {
return status >= 300 && status < 400 && status !== 304;
}

function getCipher(
{ keyExchange, keyExchangeGroup, cipher }: Protocol.Network.SecurityDetails,
protocol: string,
url: string,
): string {
const key = `${keyExchange} ${keyExchangeGroup} ${cipher}`;
const mapping: Record<string, string> = {
"ECDHE_RSA X25519 AES_128_GCM": "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256",
"ECDHE_RSA X25519 AES_256_GCM": "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384",
" X25519Kyber768Draft00 AES_128_GCM": "TLS_AES_128_GCM_SHA256",
" X25519 AES_128_GCM": "TLS_AES_128_GCM_SHA256",
" X25519Kyber768Draft00 AES_256_GCM": "TLS_AES_256_GCM_SHA384",
" X25519 AES_256_GCM": "TLS_AES_256_GCM_SHA384",
" P-256 AES_256_GCM": "TLS_AES_256_GCM_SHA384",
};
let cipherString = mapping[key] || "";
if (!cipherString && protocol === "tls/1.3") {
switch (keyExchangeGroup) {
case "AES_256_GCM":
cipherString = "TLS_AES_256_GCM_SHA384";
break;

case "AES_128_GCM":
cipherString = "TLS_AES_128_GCM_SHA256";
break;
}
}
if (!cipherString) {
logger.debug("No cipher for", { key, url });
}
return cipherString;
}
Loading