feat(Network): introduce response.securityDetails() method (#1880)

This patch:
- introduces `SecurityDetails` class that exposes a set of fields that describe properties of secure connection
- introduces method `response.securityDetails()` that returns an instance of `SecurityDetails` object.
This commit is contained in:
Tomáš Trnka 2018-02-13 20:26:18 +01:00 committed by Andrey Lushnikov
parent 700244a29a
commit 856c431914
3 changed files with 103 additions and 2 deletions

View File

@ -215,9 +215,16 @@
* [response.json()](#responsejson)
* [response.ok()](#responseok)
* [response.request()](#responserequest)
* [response.securityDetails()](#responsesecuritydetails)
* [response.status()](#responsestatus)
* [response.text()](#responsetext)
* [response.url()](#responseurl)
- [class: SecurityDetails](#class-securitydetails)
* [securityDetails.issuer()](#securitydetailsissuer)
* [securityDetails.protocol()](#securitydetailsprotocol)
* [securityDetails.subjectName()](#securitydetailssubjectname)
* [securityDetails.validFrom()](#securitydetailsvalidfrom)
* [securityDetails.validTo()](#securitydetailsvalidto)
- [class: Target](#class-target)
* [target.createCDPSession()](#targetcreatecdpsession)
* [target.page()](#targetpage)
@ -2420,6 +2427,9 @@ Contains a boolean stating whether the response was successful (status in the ra
#### response.request()
- returns: <[Request]> A matching [Request] object.
#### response.securityDetails()
- returns: <[SecurityDetails]> An object with security details associated with the response. From the original object only the fields `subjectName`, `"issuer"`, `"validFrom"`, `"validTo"`, `"protocol"` are extracted.
#### response.status()
- returns: <[number]>
@ -2433,6 +2443,25 @@ Contains the status code of the response (e.g., 200 for a success).
Contains the URL of the response.
### class: SecurityDetails
[SecurityDetails] class represents responses which are received by page.
#### securityDetails.issuer()
- returns: <[string]> A string with the name of issuer of the certificate.
#### securityDetails.protocol()
- returns: <[string]> String with the security protocol, eg. "TLS 1.2".
#### securityDetails.subjectName()
- returns: <[string]> Name of the subject to which the certificate was issued to.
#### securityDetails.validFrom()
- returns: <[number]> Timestamp stating the start of validity of the certificate.
#### securityDetails.validTo()
- returns: <[number]> Timestamp stating the end of validity of the certificate.
### class: Target
#### target.createCDPSession()

View File

@ -253,7 +253,7 @@ class NetworkManager extends EventEmitter {
if (!request)
return;
const response = new Response(this._client, request, event.response.status, event.response.headers,
event.response.fromDiskCache, event.response.fromServiceWorker);
event.response.fromDiskCache, event.response.fromServiceWorker, event.response.securityDetails);
request._response = response;
this.emit(NetworkManager.Events.Response, response);
}
@ -498,10 +498,11 @@ class Response {
* @param {!Request} request
* @param {number} status
* @param {!Object} headers
* @param {!Object} securityDetails
* @param {boolean} fromDiskCache
* @param {boolean} fromServiceWorker
*/
constructor(client, request, status, headers, fromDiskCache, fromServiceWorker) {
constructor(client, request, status, headers, fromDiskCache, fromServiceWorker, securityDetails = null) {
this._client = client;
this._request = request;
this._contentPromise = null;
@ -513,6 +514,15 @@ class Response {
this._headers = {};
for (const key of Object.keys(headers))
this._headers[key.toLowerCase()] = headers[key];
this._securityDetails = {};
if (securityDetails) {
this._securityDetails = new SecurityDetails(
securityDetails['subjectName'],
securityDetails['issuer'],
securityDetails['validFrom'],
securityDetails['validTo'],
securityDetails['protocol']);
}
}
/**
@ -543,6 +553,13 @@ class Response {
return this._headers;
}
/**
* @return {!SecurityDetails|Object}
*/
securityDetails() {
return this._securityDetails;
}
/**
* @return {!Promise<!Buffer>}
*/
@ -631,6 +648,59 @@ function generateRequestHash(request) {
return JSON.stringify(hash);
}
class SecurityDetails {
/**
* @param {string} subjectName
* @param {string} issuer
* @param {number} validFrom
* @param {number} validTo
* @param {string} protocol
*/
constructor(subjectName, issuer, validFrom, validTo, protocol) {
this._subjectName = subjectName;
this._issuer = issuer;
this._validFrom = validFrom;
this._validTo = validTo;
this._protocol = protocol;
}
/**
* @return {string}
*/
subjectName() {
return this._subjectName;
}
/**
* @return {string}
*/
issuer() {
return this._issuer;
}
/**
* @return {number}
*/
validFrom() {
return this._validFrom;
}
/**
* @return {number}
*/
validTo() {
return this._validTo;
}
/**
* @return {string}
*/
protocol() {
return this._protocol;
}
}
NetworkManager.Events = {
Request: 'request',
Response: 'response',

View File

@ -150,6 +150,8 @@ describe('Puppeteer', function() {
const response = await page.goto(httpsServer.EMPTY_PAGE).catch(e => error = e);
expect(error).toBe(null);
expect(response.ok()).toBe(true);
expect(response.securityDetails()).toBeTruthy();
expect(response.securityDetails().protocol()).toBe('TLS 1.2');
browser.close();
});
it('should reject all promises when browser is closed', async() => {