Skip to content

Support cache and conditional requests to fetch public keys from GET /meta/public_keys/copilot_api #9

@gr2m

Description

@gr2m

Follow up to #8.

The GET /meta/public_keys/copilot_api route returns an Etag header, which it supports conditional requests.

$ gh api meta/public_keys/copilot_api -i

HTTP/2.0 200 OK
Access-Control-Allow-Origin: *
Access-Control-Expose-Headers: ETag, Link, Location, Retry-After, X-GitHub-OTP, X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Used, X-RateLimit-Resource, X-RateLimit-Reset, X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Poll-Interval, X-GitHub-Media-Type, X-GitHub-SSO, X-GitHub-Request-Id, Deprecation, Sunset
Cache-Control: private, max-age=60, s-maxage=60
Content-Security-Policy: default-src 'none'
Content-Type: application/json; charset=utf-8
Date: Wed, 28 Aug 2024 19:13:39 GMT
Etag: W/"bdd20483b090130ff6ab72f309a50af6732f8f7cbb8909285f163311fede0fb3"
Referrer-Policy: origin-when-cross-origin, strict-origin-when-cross-origin
Server: github.com
Strict-Transport-Security: max-age=31536000; includeSubdomains; preload
Vary: Accept, Authorization, Cookie, X-GitHub-OTP,Accept-Encoding, Accept, X-Requested-With
X-Accepted-Oauth-Scopes: 
X-Content-Type-Options: nosniff
X-Frame-Options: deny
X-Github-Api-Version-Selected: 2022-11-28
X-Github-Media-Type: github.v3; format=json
X-Github-Request-Id: C8CA:373C9D:CC38E0:CD9C04:66CF76E3
X-Oauth-Client-Id: 178c6fc778ccc68e1d6a
X-Oauth-Scopes: codespace, gist, read:org, repo, workflow
X-Ratelimit-Limit: 15000
X-Ratelimit-Remaining: 14954
X-Ratelimit-Reset: 1724872662
X-Ratelimit-Resource: core
X-Ratelimit-Used: 46
X-Xss-Protection: 0

{
  "public_keys": [
    {
      "key_identifier": "4fe6b016179b74078ade7581abf4e84fb398c6fae4fb973972235b84fcd70ca3",
      "key": "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAELPuPiLVQbHY/clvpNnY+0BzYIXgo\nS0+XhEkTWUZEEznIVpS3rQseDTG6//gEWr4j9fY35+dGOxwOx3Z9mK3i7w==\n-----END PUBLIC KEY-----\n",
      "is_current": true
    },
    {
      "key_identifier": "df3454252d91570ae1bc597182d1183c7a8d42ff0ae96e0f2be4ba278d776546",
      "key": "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEl5xbyr5bmETCJzqAvDnYl1ZKJrkf\n89Nyq5j06TTKrnHXXDw4FYNY1uF2S/w6EOaxbf9BxOidCLvjJ8ZgKzNpww==\n-----END PUBLIC KEY-----\n",
      "is_current": false
    }
  ]
}

In order to implement caching of the public keys, we need to return the etag hash as "cache ID" and the keys in the fetchVerificationKeys() method, and return the cache ID and the keys as part of verifyRequestByKeyId()

This will introduce a breaking change

const { keys, cacheId } = fetchVerificationKeys()

Once received, the result can be used as an optional cache argument, which will result in sending a conditional request

const result1 = fetchVerificationKeys()
const verificationKeysCache = { id: result1.cacheId, keys: result1.keys }
const result2 =fetchVerificationKeys({ cache: verificationKeysCache }) 

In this example, the 2nd request will get a 304 and return the keys that were passed as options.cache.keys

The change to verifyRequestByKeyId() would be similar

const { isValid, cacheId } = verifyRequestByKeyId(rawBody, signature, keyId, { cache })

This is an optimization and can be done later. Pull request welcome!

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions