Skip to content

Commit 6a1c7af

Browse files
authored
Merge pull request #531 from ampproject/master
Release version 7 of AMP cache transforms
2 parents f36311a + 63d1859 commit 6a1c7af

File tree

298 files changed

+26325
-92474
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

298 files changed

+26325
-92474
lines changed

docs/cache_requirements.md

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -34,18 +34,17 @@ These include:
3434
it cannot have a value (i.e. `no-cache=some-header` is disallowed).
3535
* The signed `content-security-policy` header must be present and comply with
3636
these rules:
37-
* `default-src`, `script-src`, `object-src`, `style-src`, and `report-uri`
38-
must equal those from the [AMP cache CSP](https://github.com/ampproject/amppackager/blob/c54d36556d56d5a604eea079ef7dc8067f67e1ea/packager/signer/signer.go#L244-L255)
37+
* `default-src`, `script-src`, `object-src`, and `style-src` must equal
38+
those from the [AMP cache CSP](https://github.com/ampproject/amppackager/blob/e581627de0f60e41cd073de8f097bd3e7259ffdf/packager/signer/signer.go#L246-L259).
3939
* `base-uri`, `block-all-mixed-content`, `font-src`, `form-action`,
40-
`manifest-src`, `referrer`, and `upgrade-insecure-requests` may be omitted
41-
or have any value
42-
* all other directives are disallowed
40+
`manifest-src`, `referrer`, `report-uri` and `upgrade-insecure-requests`
41+
may be omitted or have any value.
42+
* All other directives are disallowed.
4343
* The signed `content-type` header must be present. Its media type must be
4444
`text/html`. Its `charset` parameter, if present, must case-insensitively
4545
equal `utf-8`.
46-
* The signed `link` header, if present, must look like [this](https://github.com/ampproject/amppackager/blob/e4bf0430ba152cfe82ccf063df92021dfc0f26a5/packager/signer/signer.go#L426)
47-
(the validation logic is currently very picky about its serialization); and
48-
have limits like [this](https://github.com/ampproject/amppackager/blob/e4bf0430ba152cfe82ccf063df92021dfc0f26a5/transformer/transformer.go#L177)
46+
* The signed `link` header, if present, must
47+
have limits like [this](https://github.com/ampproject/amppackager/blob/a5bb0248b0fd0bf2ad6e4d47ca444261c6409e3f/transformer/transformer.go#L201)
4948
(e.g. max 20 urls, rel=preload only, as=script|style only). URLs must be
5049
limited to `cdn.ampproject.org` and the allowlisted [font provider URLs](https://github.com/ampproject/amphtml/blob/b0ff92429923c86f3973009a84ff02f4f1868b4d/validator/validator-main.protoascii#L310).
5150
* There must not be a signed `variant-key-04` or `variants-04` header.

go.mod

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,9 @@ require (
1515
github.com/pquerna/cachecontrol v0.0.0-20180306154005-525d0eb5f91d
1616
github.com/prometheus/client_golang v1.1.0
1717
github.com/stretchr/testify v1.4.0
18+
github.com/twifkak/crypto v0.0.0-20210326012946-1fce8924335d
1819
golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4
19-
golang.org/x/net v0.0.0-20190930134127-c5a3c61f89f3
20+
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110
2021
google.golang.org/grpc v1.27.0
2122
google.golang.org/protobuf v1.25.0
2223
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 // indirect

go.sum

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -291,6 +291,9 @@ github.com/timewasted/linode v0.0.0-20160829202747-37e84520dcf7 h1:CpHxIaZzVy26G
291291
github.com/timewasted/linode v0.0.0-20160829202747-37e84520dcf7/go.mod h1:imsgLplxEC/etjIhdr3dNzV3JeT27LbVu5pYWm0JCBY=
292292
github.com/transip/gotransip v0.0.0-20190812104329-6d8d9179b66f h1:clyOmELPZd2LuFEyuo1mP6RXpbAW75PwD+RfDj4kBm0=
293293
github.com/transip/gotransip v0.0.0-20190812104329-6d8d9179b66f/go.mod h1:i0f4R4o2HM0m3DZYQWsj6/MEowD57VzoH0v3d7igeFY=
294+
github.com/twifkak/crypto v0.0.0-20210326012350-5f9a47aaade5 h1:Oota0BCNCpjP5Q7jeGhL9YUntFZ3DsIS9gYGZicdG5w=
295+
github.com/twifkak/crypto v0.0.0-20210326012946-1fce8924335d h1:BBr+XPoeoGMHJIe/QTrEStIeqtPR6vd6VQkPxZpmvtg=
296+
github.com/twifkak/crypto v0.0.0-20210326012946-1fce8924335d/go.mod h1:rNU8gVCuI2stMMtBCigkYDjse6rFX/5ygOfUGQpGsbY=
294297
github.com/uber-go/atomic v1.3.2 h1:Azu9lPBWRNKzYXSIwRfgRuDuS0YKsK4NFhiQv98gkxo=
295298
github.com/uber-go/atomic v1.3.2/go.mod h1:/Ct5t2lcmbJ4OSe/waGBoaVvVqtO0bmtfVNex1PFV8g=
296299
github.com/ugorji/go/codec v0.0.0-20181209151446-772ced7fd4c2 h1:EICbibRW4JNKMcY+LsWmuwob+CRS1BmdRdjphAm9mH4=
@@ -343,6 +346,9 @@ golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b h1:ag/x1USPSsqHud38I9BAC88qd
343346
golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
344347
golang.org/x/sys v0.0.0-20190801041406-cbf593c0f2f3 h1:4y9KwBHBgBNwDbtu44R5o1fdOCQUEXhbk/P4A9WmJq0=
345348
golang.org/x/sys v0.0.0-20190801041406-cbf593c0f2f3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
349+
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68 h1:nxC68pudNYkKU6jWhgrqdreuFiOQWj1Fs7T3VrH4Pjw=
350+
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
351+
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
346352
golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg=
347353
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
348354
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=

packager/certcache/certcache.go

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -429,9 +429,9 @@ func (this *CertCache) readOCSP(allowRetries bool) ([]byte, time.Time, error) {
429429

430430
// Print # of retries, wait for specified time and returned updated wait time.
431431
func waitForSpecifiedTime(waitTimeInMinutes int, numRetries int) int {
432-
log.Printf("Retrying OCSP server: retry #%d\n", numRetries)
432+
log.Printf("Retrying OCSP server: retry #%d", numRetries)
433433
// Wait using exponential backoff.
434-
log.Printf("Waiting for %d minute(s)\n", waitTimeInMinutes)
434+
log.Printf("Waiting for %d minute(s)", waitTimeInMinutes)
435435
waitTimeDuration := time.Duration(waitTimeInMinutes) * time.Minute
436436
// For exponential backoff.
437437
newWaitTimeInMinutes := 2 * waitTimeInMinutes
@@ -650,11 +650,28 @@ func (this *CertCache) fetchOCSP(orig []byte, certs []*x509.Certificate, ocspUpd
650650
log.Println("OCSP nextUpdate in the past:", resp.NextUpdate)
651651
return orig
652652
}
653+
for _, test := range []struct {
654+
name string
655+
value time.Time
656+
}{
657+
{"thisUpdate", resp.ThisUpdate},
658+
{"nextUpdate", resp.NextUpdate},
659+
{"producedAt", resp.ProducedAt},
660+
} {
661+
if test.value.Before(certs[0].NotBefore) {
662+
log.Printf("OCSP %s %+v before certificate notBefore %+v", test.name, test.value, certs[0].NotBefore)
663+
return orig
664+
}
665+
if test.value.After(certs[0].NotAfter) {
666+
log.Printf("OCSP %s %+v after certificate notAfter %+v", test.name, test.value, certs[0].NotAfter)
667+
return orig
668+
}
669+
}
653670
// OCSP duration must be <=7 days, per
654671
// https://wicg.github.io/webpackage/draft-yasskin-httpbis-origin-signed-exchanges-impl.html#cross-origin-trust.
655672
// Serving these responses may cause UAs to reject the SXG.
656673
if resp.NextUpdate.Sub(resp.ThisUpdate) > time.Hour*24*7 {
657-
log.Printf("OCSP nextUpdate %+v too far ahead of thisUpdate %+v\n", resp.NextUpdate, resp.ThisUpdate)
674+
log.Printf("OCSP nextUpdate %+v too far ahead of thisUpdate %+v", resp.NextUpdate, resp.ThisUpdate)
658675
return orig
659676
}
660677
return respBytes

packager/certcache/certcache_test.go

Lines changed: 68 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ import (
3333
pkgt "github.com/ampproject/amppackager/packager/testing"
3434
"github.com/ampproject/amppackager/packager/util"
3535
"github.com/stretchr/testify/suite"
36+
ocsptest "github.com/twifkak/crypto/ocsp"
3637
"golang.org/x/crypto/ocsp"
3738
)
3839

@@ -48,16 +49,20 @@ var caKey = func() *rsa.PrivateKey {
4849
return key.(*rsa.PrivateKey)
4950
}()
5051

51-
func FakeOCSPResponse(thisUpdate time.Time) ([]byte, error) {
52-
template := ocsp.Response{
52+
// FakeOCSPResponse returns a DER-encoded fake OCSP response. producedAt is
53+
// rounded up to the nearest minute, rather than the default ocsp lib behavior
54+
// of rounding down, so that calls to this function with producedAt ==
55+
// thisUpdate return a valid response.
56+
func FakeOCSPResponse(thisUpdate, producedAt time.Time) ([]byte, error) {
57+
template := ocsptest.Response{
5358
Status: ocsp.Good,
5459
SerialNumber: pkgt.B3Certs[0].SerialNumber,
5560
ThisUpdate: thisUpdate,
5661
NextUpdate: thisUpdate.Add(7 * 24 * time.Hour),
5762
RevokedAt: thisUpdate.AddDate( /*years=*/ 0 /*months=*/, 0 /*days=*/, 365),
5863
RevocationReason: ocsp.Unspecified,
5964
}
60-
return ocsp.CreateResponse(caCert, caCert, template, caKey)
65+
return ocsptest.CreateResponse(caCert, caCert, template, caKey, producedAt.Add(1*time.Minute))
6166
}
6267

6368
type CertCacheSuite struct {
@@ -110,9 +115,14 @@ func (this *CertCacheSuite) TearDownSuite() {
110115
}
111116

112117
func (this *CertCacheSuite) SetupTest() {
118+
// Set fake clock to a time 8 days past the NotBefore of the cert, so
119+
// our tests can backdate OCSPs to test expiry logic, without
120+
// accidentally hitting the requirement that OCSPs must postdate certs.
113121
this.fakeClock = pkgt.NewFakeClock()
122+
this.fakeClock.SecondsSince0 = pkgt.B3Certs[0].NotBefore.Add(8 * 24 * time.Hour).Sub(time.Unix(0, 0))
123+
now := this.fakeClock.Now()
114124
var err error
115-
this.fakeOCSP, err = FakeOCSPResponse(this.fakeClock.Now())
125+
this.fakeOCSP, err = FakeOCSPResponse(now, now)
116126
this.Require().NoError(err, "creating fake OCSP response")
117127

118128
this.ocspHandler = func(resp http.ResponseWriter, req *http.Request) {
@@ -193,11 +203,30 @@ func (this *CertCacheSuite) TestCertCacheIsHealthy() {
193203
this.Assert().NoError(this.handler.IsHealthy())
194204
}
195205

206+
func (this *CertCacheSuite) TestOCSPInvalidThisUpdate() {
207+
// Set fake clock equal to cert NotBefore, so we can produce an OCSP
208+
// where "now" is within its ThisUpdate/NextUpdate window, but the OCSP
209+
// is itself outside of the cert's NotBefore/NotAfter window.
210+
this.fakeClock.SecondsSince0 = pkgt.B3Certs[0].NotBefore.Sub(time.Unix(0, 0))
211+
212+
err := os.Remove(filepath.Join(this.tempDir, "ocsp"))
213+
this.Require().NoError(err, "deleting OCSP tempfile")
214+
215+
// Build an OCSP response that's not expired, but invalid because it predates the cert:
216+
invalidOCSP, err := FakeOCSPResponse(this.fakeClock.Now().Add(-1*24*time.Hour), this.fakeClock.Now())
217+
this.Require().NoError(err, "creating invalid OCSP response")
218+
this.fakeOCSP = invalidOCSP
219+
this.Require().True(this.ocspServerCalled(func() {
220+
this.handler, err = this.New()
221+
this.Require().EqualError(err, "initializing CertCache: Missing OCSP response.")
222+
}))
223+
}
224+
196225
func (this *CertCacheSuite) TestCertCacheIsNotHealthy() {
197226
// Prime memory cache with a past-midpoint OCSP:
198227
err := os.Remove(filepath.Join(this.tempDir, "ocsp"))
199228
this.Require().NoError(err, "deleting OCSP tempfile")
200-
this.fakeOCSP, err = FakeOCSPResponse(this.fakeClock.Now().Add(-4 * 24 * time.Hour))
229+
this.fakeOCSP, err = FakeOCSPResponse(this.fakeClock.Now().Add(-4*24*time.Hour), this.fakeClock.Now())
201230
this.Require().NoError(err, "creating stale OCSP response")
202231
this.Require().True(this.ocspServerCalled(func() {
203232
this.handler, err = this.New()
@@ -230,7 +259,7 @@ func (this *CertCacheSuite) TestOCSP() {
230259
resp := pkgt.NewRequest(this.T(), this.mux(), "/amppkg/cert/"+pkgt.CertName).Do()
231260
this.Assert().Equal(http.StatusOK, resp.StatusCode, "incorrect status: %#v", resp)
232261
// 302400 is 3.5 days. max-age is slightly less because of the time between fake OCSP generation and cert-chain response.
233-
this.Assert().Equal("public, max-age=302387", resp.Header.Get("Cache-Control"))
262+
this.Assert().Equal("public, max-age=302388", resp.Header.Get("Cache-Control"))
234263
cbor := this.DecodeCBOR(resp.Body)
235264
this.Assert().Equal(this.fakeOCSP, cbor["ocsp"])
236265
}
@@ -253,7 +282,7 @@ func (this *CertCacheSuite) TestOCSPExpiry() {
253282
// Prime memory and disk cache with a past-midpoint OCSP:
254283
err := os.Remove(filepath.Join(this.tempDir, "ocsp"))
255284
this.Require().NoError(err, "deleting OCSP tempfile")
256-
this.fakeOCSP, err = FakeOCSPResponse(this.fakeClock.Now().Add(-4 * 24 * time.Hour))
285+
this.fakeOCSP, err = FakeOCSPResponse(this.fakeClock.Now().Add(-4*24*time.Hour), this.fakeClock.Now())
257286
this.Require().NoError(err, "creating expired OCSP response")
258287
this.Require().True(this.ocspServerCalled(func() {
259288
this.handler, err = this.New()
@@ -275,15 +304,16 @@ func (this *CertCacheSuite) TestOCSPUpdateFromDisk() {
275304
// Prime memory cache with a past-midpoint OCSP:
276305
err := os.Remove(filepath.Join(this.tempDir, "ocsp"))
277306
this.Require().NoError(err, "deleting OCSP tempfile")
278-
this.fakeOCSP, err = FakeOCSPResponse(this.fakeClock.Now().Add(-4 * 24 * time.Hour))
307+
this.fakeOCSP, err = FakeOCSPResponse(this.fakeClock.Now().Add(-4*24*time.Hour), this.fakeClock.Now())
279308
this.Require().NoError(err, "creating stale OCSP response")
280309
this.Require().True(this.ocspServerCalled(func() {
281310
this.handler, err = this.New()
282311
this.Require().NoError(err, "reinstantiating CertCache")
283312
}))
284313

285314
// Prime disk cache with a fresh OCSP.
286-
freshOCSP, err := FakeOCSPResponse(this.fakeClock.Now())
315+
now := this.fakeClock.Now()
316+
freshOCSP, err := FakeOCSPResponse(now, now)
287317
this.Require().NoError(err, "creating fresh OCSP response")
288318
err = ioutil.WriteFile(filepath.Join(this.tempDir, "ocsp"), freshOCSP, 0644)
289319
this.Require().NoError(err, "writing fresh OCSP response to disk")
@@ -314,11 +344,11 @@ func (this *CertCacheSuite) TestOCSPExpiredViaHTTPHeaders() {
314344
}))
315345
}
316346

317-
func (this *CertCacheSuite) TestOCSPIgnoreInvalidUpdate() {
347+
func (this *CertCacheSuite) TestOCSPIgnoreExpiredNextUpdate() {
318348
// Prime memory and disk cache with a past-midpoint OCSP:
319349
err := os.Remove(filepath.Join(this.tempDir, "ocsp"))
320350
this.Require().NoError(err, "deleting OCSP tempfile")
321-
staleOCSP, err := FakeOCSPResponse(this.fakeClock.Now().Add(-4 * 24 * time.Hour))
351+
staleOCSP, err := FakeOCSPResponse(this.fakeClock.Now().Add(-4*24*time.Hour), this.fakeClock.Now())
322352
this.Require().NoError(err, "creating stale OCSP response")
323353
this.fakeOCSP = staleOCSP
324354
this.Require().True(this.ocspServerCalled(func() {
@@ -327,7 +357,7 @@ func (this *CertCacheSuite) TestOCSPIgnoreInvalidUpdate() {
327357
}))
328358

329359
// Try to update with an invalid OCSP:
330-
this.fakeOCSP, err = FakeOCSPResponse(this.fakeClock.Now().Add(-8 * 24 * time.Hour))
360+
this.fakeOCSP, err = FakeOCSPResponse(this.fakeClock.Now().Add(-8*24*time.Hour), this.fakeClock.Now())
331361
this.Require().NoError(err, "creating expired OCSP response")
332362
this.Assert().True(this.ocspServerCalled(func() {
333363
_, _, err := this.handler.readOCSP(true)
@@ -340,6 +370,32 @@ func (this *CertCacheSuite) TestOCSPIgnoreInvalidUpdate() {
340370
this.Assert().Equal(staleOCSP, ocsp)
341371
}
342372

373+
func (this *CertCacheSuite) TestOCSPIgnoreInvalidProducedAt() {
374+
// Prime memory and disk cache with a past-midpoint OCSP:
375+
err := os.Remove(filepath.Join(this.tempDir, "ocsp"))
376+
this.Require().NoError(err, "deleting OCSP tempfile")
377+
staleOCSP, err := FakeOCSPResponse(this.fakeClock.Now().Add(-4*24*time.Hour), this.fakeClock.Now())
378+
this.Require().NoError(err, "creating stale OCSP response")
379+
this.fakeOCSP = staleOCSP
380+
this.Require().True(this.ocspServerCalled(func() {
381+
this.handler, err = this.New()
382+
this.Require().NoError(err, "reinstantiating CertCache")
383+
}))
384+
385+
// Try to update with an OCSP with an invalid ProducedAt:
386+
this.fakeOCSP, err = FakeOCSPResponse(this.fakeClock.Now().Add(-4*24*time.Hour), time.Unix(0, 0))
387+
this.Require().NoError(err, "creating invalid OCSP response")
388+
this.Assert().True(this.ocspServerCalled(func() {
389+
_, _, err := this.handler.readOCSP(true)
390+
this.Require().NoError(err, "updating OCSP")
391+
}))
392+
393+
// Verify that the invalid update doesn't squash the valid cache entry.
394+
ocsp, _, err := this.handler.readOCSP(true)
395+
this.Require().NoError(err, "reading OCSP")
396+
this.Assert().Equal(staleOCSP, ocsp)
397+
}
398+
343399
func (this *CertCacheSuite) TestPopulateCertCache() {
344400
certCache, err := PopulateCertCache(
345401
&util.Config{

packager/signer/signer.go

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -247,6 +247,7 @@ func MutateFetchedContentSecurityPolicy(fetched string) string {
247247
"report-uri https://csp.withgoogle.com/csp/amp;" +
248248
"script-src blob: https://cdn.ampproject.org/rtv/ " +
249249
"https://cdn.ampproject.org/v0.js " +
250+
"https://cdn.ampproject.org/v0.mjs " +
250251
"https://cdn.ampproject.org/v0/ " +
251252
"https://cdn.ampproject.org/lts/ " +
252253
"https://cdn.ampproject.org/viewer/;" +
@@ -454,7 +455,13 @@ func formatLinkHeader(preloads []*rpb.Metadata_Preload) (string, error) {
454455
var value strings.Builder
455456
value.WriteByte('<')
456457
value.WriteString(u.String())
457-
value.WriteString(">;rel=preload;as=")
458+
value.WriteString(">;rel=")
459+
if preload.Module {
460+
value.WriteString("modulepreload")
461+
} else {
462+
value.WriteString("preload")
463+
}
464+
value.WriteString(";as=")
458465
value.WriteString(preload.As)
459466
for _, attr := range preload.GetAttributes() {
460467
value.WriteByte(';')

packager/signer/signer_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -468,7 +468,7 @@ func (this *SignerSuite) TestMutatesCspHeaders() {
468468
"block-all-mixed-content;"+
469469
"default-src * blob: data:;"+
470470
"report-uri https://csp.withgoogle.com/csp/amp;"+
471-
"script-src blob: https://cdn.ampproject.org/rtv/ https://cdn.ampproject.org/v0.js https://cdn.ampproject.org/v0/ https://cdn.ampproject.org/lts/ https://cdn.ampproject.org/viewer/;"+
471+
"script-src blob: https://cdn.ampproject.org/rtv/ https://cdn.ampproject.org/v0.js https://cdn.ampproject.org/v0.mjs https://cdn.ampproject.org/v0/ https://cdn.ampproject.org/lts/ https://cdn.ampproject.org/viewer/;"+
472472
"style-src 'unsafe-inline' https://cdn.materialdesignicons.com https://cloud.typography.com https://fast.fonts.net https://fonts.googleapis.com https://maxcdn.bootstrapcdn.com https://p.typekit.net https://pro.fontawesome.com https://use.fontawesome.com https://use.typekit.net;"+
473473
"object-src 'none'",
474474
exchange.ResponseHeaders.Get("Content-Security-Policy"))

packager/testing/testing.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -146,7 +146,7 @@ func (r *Request) Do() *http.Response {
146146
}
147147

148148
type FakeClock struct {
149-
secondsSince0 time.Duration
149+
SecondsSince0 time.Duration
150150
Delta time.Duration
151151
}
152152

@@ -155,7 +155,7 @@ func NewFakeClock() *FakeClock {
155155
}
156156

157157
func (this *FakeClock) Now() time.Time {
158-
secondsSince0 := this.secondsSince0
159-
this.secondsSince0 = secondsSince0 + this.Delta
158+
secondsSince0 := this.SecondsSince0
159+
this.SecondsSince0 = secondsSince0 + this.Delta
160160
return time.Unix(0, 0).Add(secondsSince0)
161161
}

packager/util/util.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,10 @@ const SignerURLPrefix = "/priv/doc"
3636
// packager's cert cache. Should be stable and unique (e.g.
3737
// content-addressing). Clients should url.PathEscape this, just in case its
3838
// format changes to need escaping in the future.
39+
//
40+
// Given a PEM-encoded certificate, this is equivalent to:
41+
// $ openssl x509 -in cert.pem -outform DER |
42+
// openssl dgst -sha256 -binary | base64 | tr /+ _- | tr -d =
3943
func CertName(cert *x509.Certificate) string {
4044
sum := sha256.Sum256(cert.Raw)
4145
return base64.RawURLEncoding.EncodeToString(sum[:])

0 commit comments

Comments
 (0)