From c07c6347e448a4b933c84b12b0f2bbe1f5bf3288 Mon Sep 17 00:00:00 2001 From: Casey Hillers Date: Tue, 20 Jun 2023 13:11:58 +0200 Subject: [PATCH] Make GitHub.auth non-nullable (#377) * add const everywhere --- example/index.dart | 2 +- example/user_info.dart | 4 ++-- lib/src/browser/xplat_browser.dart | 2 +- lib/src/common/github.dart | 21 ++++++++------------- lib/src/common/util/auth.dart | 4 ++-- lib/src/common/xplat_common.dart | 2 +- lib/src/server/xplat_server.dart | 2 +- test/common/github_test.dart | 19 ++++++++++++++++++- test/experiment/crawler.dart | 2 +- test/git_test.dart | 4 ++-- test/scenarios_test.dart | 4 ++-- 11 files changed, 39 insertions(+), 27 deletions(-) diff --git a/example/index.dart b/example/index.dart index 3a0f10b2..42851c96 100644 --- a/example/index.dart +++ b/example/index.dart @@ -3,7 +3,7 @@ import 'common.dart'; void main() { final tokenInput = querySelector('#token') as InputElement; - tokenInput.value = github.auth!.token ?? ''; + tokenInput.value = github.auth.token ?? ''; window.sessionStorage['GITHUB_TOKEN'] = tokenInput.value!; tokenInput.onKeyUp.listen((_) { window.sessionStorage['GITHUB_TOKEN'] = tokenInput.value!; diff --git a/example/user_info.dart b/example/user_info.dart index a5113646..071c2820 100644 --- a/example/user_info.dart +++ b/example/user_info.dart @@ -59,8 +59,8 @@ void loadUser() { }); }); - if (github.auth!.token != null) { - localToken!.value = github.auth!.token; + if (github.auth.token != null) { + localToken!.value = github.auth.token; loadBtn.click(); } } diff --git a/lib/src/browser/xplat_browser.dart b/lib/src/browser/xplat_browser.dart index 79aeeb17..71bed55a 100644 --- a/lib/src/browser/xplat_browser.dart +++ b/lib/src/browser/xplat_browser.dart @@ -11,7 +11,7 @@ Authentication findAuthenticationFromEnvironment() { // search the query string parameters first var auth = findAuthenticationInMap(_parseQuery(window.location.href)); auth ??= findAuthenticationInMap(window.sessionStorage); - return auth ?? Authentication.anonymous(); + return auth ?? const Authentication.anonymous(); } /// Parse the query string to a parameter `Map` diff --git a/lib/src/common/github.dart b/lib/src/common/github.dart index 62358bd8..ffddef00 100644 --- a/lib/src/common/github.dart +++ b/lib/src/common/github.dart @@ -19,12 +19,11 @@ class GitHub { /// [endpoint] is the api endpoint to use /// [auth] is the authentication information GitHub({ - Authentication? auth, + this.auth = const Authentication.anonymous(), this.endpoint = 'https://api.github.com', this.version = '2022-11-28', http.Client? client, - }) : auth = auth ?? Authentication.anonymous(), - client = client ?? http.Client(); + }) : client = client ?? http.Client(); static const _ratelimitLimitHeader = 'x-ratelimit-limit'; static const _ratelimitResetHeader = 'x-ratelimit-reset'; @@ -34,7 +33,7 @@ class GitHub { static const versionHeader = 'X-GitHub-Api-Version'; /// Authentication Information - Authentication? auth; + final Authentication auth; /// API Endpoint final String endpoint; @@ -369,16 +368,16 @@ class GitHub { headers['Accept'] = preview; } - if (auth!.isToken) { - headers.putIfAbsent('Authorization', () => 'token ${auth!.token}'); - } else if (auth!.isBasic) { + if (auth.isToken) { + headers.putIfAbsent('Authorization', () => 'token ${auth.token}'); + } else if (auth.isBasic) { final userAndPass = - base64Encode(utf8.encode('${auth!.username}:${auth!.password}')); + base64Encode(utf8.encode('${auth.username}:${auth.password}')); headers.putIfAbsent('Authorization', () => 'basic $userAndPass'); } // See https://docs.github.com/en/rest/overview/resources-in-the-rest-api?apiVersion=2022-11-28#user-agent-required - headers.putIfAbsent('User-Agent', () => auth?.username ?? 'github.dart'); + headers.putIfAbsent('User-Agent', () => auth.username ?? 'github.dart'); if (method == 'PUT' && body == null) { headers.putIfAbsent('Content-Length', () => '0'); @@ -493,10 +492,6 @@ class GitHub { /// Disposes of this GitHub Instance. /// No other methods on this instance should be called after this method is called. void dispose() { - // Destroy the Authentication Information - // This is needed for security reasons. - auth = null; - // Closes the HTTP Client client.close(); } diff --git a/lib/src/common/util/auth.dart b/lib/src/common/util/auth.dart index 925ffc93..b287f16c 100644 --- a/lib/src/common/util/auth.dart +++ b/lib/src/common/util/auth.dart @@ -10,12 +10,12 @@ class Authentication { final String? password; /// Creates an [Authentication] instance that uses the specified OAuth2 [token]. - Authentication.withToken(this.token) + const Authentication.withToken(this.token) : username = null, password = null; /// Creates an [Authentication] instance that has no authentication. - Authentication.anonymous() + const Authentication.anonymous() : token = null, username = null, password = null; diff --git a/lib/src/common/xplat_common.dart b/lib/src/common/xplat_common.dart index cc0bfcbb..1c60f906 100644 --- a/lib/src/common/xplat_common.dart +++ b/lib/src/common/xplat_common.dart @@ -10,7 +10,7 @@ import 'package:github/src/common.dart'; /// In both contexts it delegates to [findAuthenticationInMap] to find the /// github token or username and password. Authentication findAuthenticationFromEnvironment() => - Authentication.anonymous(); + const Authentication.anonymous(); /// Checks the passed in map for keys in [COMMON_GITHUB_TOKEN_ENV_KEYS]. /// The first one that exists is used as the github token to call [Authentication.withToken] with. diff --git a/lib/src/server/xplat_server.dart b/lib/src/server/xplat_server.dart index 3bd6e100..a6c85d02 100644 --- a/lib/src/server/xplat_server.dart +++ b/lib/src/server/xplat_server.dart @@ -27,5 +27,5 @@ Authentication findAuthenticationFromEnvironment() { } return findAuthenticationInMap(Platform.environment) ?? - Authentication.anonymous(); + const Authentication.anonymous(); } diff --git a/test/common/github_test.dart b/test/common/github_test.dart index 4f7d6727..97ce2930 100644 --- a/test/common/github_test.dart +++ b/test/common/github_test.dart @@ -1,6 +1,6 @@ import 'dart:io'; -import 'package:github/src/common/github.dart'; +import 'package:github/src/common.dart'; import 'package:http/http.dart'; import 'package:http/testing.dart'; import 'package:test/test.dart'; @@ -38,5 +38,22 @@ void main() { final userAgent = request!.headers['User-Agent']; expect(userAgent, 'github.dart'); }); + + test('anonymous auth passes no authorization header', () async { + Request? request; + final client = MockClient((r) async { + request = r; + return Response('{}', HttpStatus.ok); + }); + + final github = GitHub( + client: client, + auth: const Authentication.anonymous(), + ); + await github.getJSON(''); // Make HTTP request + + expect(request, isNotNull); + expect(request!.headers.containsKey('Authorization'), isFalse); + }); }); } diff --git a/test/experiment/crawler.dart b/test/experiment/crawler.dart index cc4e23ee..7dd8e737 100644 --- a/test/experiment/crawler.dart +++ b/test/experiment/crawler.dart @@ -1,7 +1,7 @@ import 'package:github/github.dart'; void main() { - final github = GitHub(auth: Authentication.anonymous()); + final github = GitHub(auth: const Authentication.anonymous()); final crawler = RepositoryCrawler( github, diff --git a/test/git_test.dart b/test/git_test.dart index 34487b95..228b3a0b 100644 --- a/test/git_test.dart +++ b/test/git_test.dart @@ -10,8 +10,8 @@ const date = '2014-10-02T15:21:29Z'; GitHub createGithub() { return GitHub( endpoint: fakeApiUrl, - auth: - Authentication.withToken('0000000000000000000000000000000000000001')); + auth: const Authentication.withToken( + '0000000000000000000000000000000000000001')); } void main() { diff --git a/test/scenarios_test.dart b/test/scenarios_test.dart index c39ceb53..70f1a789 100644 --- a/test/scenarios_test.dart +++ b/test/scenarios_test.dart @@ -28,8 +28,8 @@ Future createGithubWithScenario(String scenario, var j = json.decode(resp.body); return GitHub( endpoint: j['url'], - auth: - Authentication.withToken('0000000000000000000000000000000000000001')); + auth: const Authentication.withToken( + '0000000000000000000000000000000000000001')); } /// Run scenario tests against ockokits fixtures-server