Verify token characters when added and when used (#3732)
diff --git a/doc/repository-spec-v2.md b/doc/repository-spec-v2.md index 06ad714..9104428 100644 --- a/doc/repository-spec-v2.md +++ b/doc/repository-spec-v2.md
@@ -133,6 +133,10 @@ authentication can only be used when `<hosted-url>` uses HTTPS. For further details on token management see: `dart pub token --help`. +The tokens are inserted verbatim in the header, therefore they have to adhere to + https://www.rfc-editor.org/rfc/rfc6750#section-2.1. This means they must match + the regex: `^[a-zA-Z0-9._~+/=-]+$`. + ### Missing Authentication or Invalid Token If the server requires authentication and the request does not carry an
diff --git a/lib/src/authentication/credential.dart b/lib/src/authentication/credential.dart index 9f7ce0d..a59c1d0 100644 --- a/lib/src/authentication/credential.dart +++ b/lib/src/authentication/credential.dart
@@ -6,6 +6,7 @@ import '../exceptions.dart'; import '../source/hosted.dart'; +import '../utils.dart'; /// Token is a structure for storing authentication credentials for third-party /// pub registries. A token holds registry [url], credential [kind] and [token] @@ -116,19 +117,26 @@ ); } + final String tokenValue; final environment = env; if (environment != null) { final value = Platform.environment[environment]; if (value == null) { - throw DataException( + dataError( 'Saved credential for "$url" pub repository requires environment ' 'variable named "$env" but not defined.', ); } - return Future.value('Bearer $value'); + tokenValue = value; + } else { + tokenValue = token!; + } + if (!isValidBearerToken(tokenValue)) { + dataError('Credential token for $url is not a valid Bearer token. ' + 'It should match `^[a-zA-Z0-9._~+/=-]+\$`'); } - return Future.value('Bearer $token'); + return Future.value('Bearer $tokenValue'); } /// Returns whether or not given [url] could be authenticated using this @@ -144,6 +152,14 @@ // Either [token] or [env] should be defined to be valid. bool isValid() => (token == null) ^ (env == null); + /// Whether [candidate] can be used as a bearer token. + /// + /// We limit tokens to be valid bearer tokens according to + /// https://www.rfc-editor.org/rfc/rfc6750#section-2.1 + static bool isValidBearerToken(String candidate) { + return RegExp(r'^[a-zA-Z0-9._~+/=-]+$').hasMatch(candidate); + } + static String _normalizeUrl(String url) { return (url.endsWith('/') ? url : '$url/').toLowerCase(); }
diff --git a/lib/src/command/token_add.dart b/lib/src/command/token_add.dart index be9d406..86f032f 100644 --- a/lib/src/command/token_add.dart +++ b/lib/src/command/token_add.dart
@@ -11,6 +11,7 @@ import '../io.dart'; import '../log.dart' as log; import '../source/hosted.dart'; +import '../utils.dart'; /// Handles the `token add` pub command. class TokenAddCommand extends PubCommand { @@ -69,6 +70,11 @@ usageException('Token is not provided.'); } + if (!Credential.isValidBearerToken(token)) { + dataError('The entered token is not a valid Bearer token. ' + 'A token may only contain `a-zA-Z0-9._~+/=-`'); + } + tokenStore.addCredential(Credential.token(hostedUrl, token)); log.message( 'Requests to "$hostedUrl" will now be authenticated using the secret '
diff --git a/test/directory_option_test.dart b/test/directory_option_test.dart index ac61887..5bc1cfd 100644 --- a/test/directory_option_test.dart +++ b/test/directory_option_test.dart
@@ -18,7 +18,7 @@ ..serve('foo', '1.0.0') ..serve('foo', '0.1.2') ..serve('bar', '1.2.3'); - await credentialsFile(globalServer, 'access token').create(); + await credentialsFile(globalServer, 'access-token').create(); globalServer.handle( RegExp('/api/packages/test_pkg/uploaders'), (request) {
diff --git a/test/lish/archives_and_uploads_a_package_test.dart b/test/lish/archives_and_uploads_a_package_test.dart index ffad2ea..dcd66cc 100644 --- a/test/lish/archives_and_uploads_a_package_test.dart +++ b/test/lish/archives_and_uploads_a_package_test.dart
@@ -18,7 +18,7 @@ test('archives and uploads a package', () async { await servePackages(); await d.validPackage.create(); - await d.credentialsFile(globalServer, 'access token').create(); + await d.credentialsFile(globalServer, 'access-token').create(); var pub = await startPublish(globalServer); await confirmPublish(pub); @@ -44,7 +44,7 @@ await d.tokensFile({ 'version': 1, 'hosted': [ - {'url': globalServer.url, 'token': 'access token'}, + {'url': globalServer.url, 'token': 'access-token'}, ] }).create(); var pub = await startPublish(globalServer); @@ -79,7 +79,7 @@ globalServer, path: '/sub/folder', overrideDefaultHostedServer: false, - environment: {'TOKEN': 'access token'}, + environment: {'TOKEN': 'access-token'}, ); await confirmPublish(pub); @@ -124,7 +124,7 @@ await d.dir(p.join(appPath, 'empty')).create(); await servePackages(); - await d.credentialsFile(globalServer, 'access token').create(); + await d.credentialsFile(globalServer, 'access-token').create(); var pub = await startPublish(globalServer); await confirmPublish(pub);
diff --git a/test/lish/cloud_storage_upload_doesnt_redirect_test.dart b/test/lish/cloud_storage_upload_doesnt_redirect_test.dart index 19b8761..fd14f85 100644 --- a/test/lish/cloud_storage_upload_doesnt_redirect_test.dart +++ b/test/lish/cloud_storage_upload_doesnt_redirect_test.dart
@@ -13,7 +13,7 @@ test("cloud storage upload doesn't redirect", () async { await servePackages(); await d.validPackage.create(); - await d.credentialsFile(globalServer, 'access token').create(); + await d.credentialsFile(globalServer, 'access-token').create(); var pub = await startPublish(globalServer); await confirmPublish(pub);
diff --git a/test/lish/cloud_storage_upload_provides_an_error_test.dart b/test/lish/cloud_storage_upload_provides_an_error_test.dart index fa3a783..78b783e 100644 --- a/test/lish/cloud_storage_upload_provides_an_error_test.dart +++ b/test/lish/cloud_storage_upload_provides_an_error_test.dart
@@ -13,7 +13,7 @@ test('cloud storage upload provides an error', () async { await servePackages(); await d.validPackage.create(); - await d.credentialsFile(globalServer, 'access token').create(); + await d.credentialsFile(globalServer, 'access-token').create(); var pub = await startPublish(globalServer); await confirmPublish(pub);
diff --git a/test/lish/does_not_include_dot_file.dart b/test/lish/does_not_include_dot_file.dart index ab0b8a8..2699c81 100644 --- a/test/lish/does_not_include_dot_file.dart +++ b/test/lish/does_not_include_dot_file.dart
@@ -30,7 +30,7 @@ test('Check if package doesn\'t include dot-files', () async { await servePackages(); - await d.credentialsFile(globalServer, 'access token').create(); + await d.credentialsFile(globalServer, 'access-token').create(); var pub = await startPublish(globalServer); await confirmPublish(pub);
diff --git a/test/lish/does_not_include_pubspec_overrides_file.dart b/test/lish/does_not_include_pubspec_overrides_file.dart index 9ff584b..126eeb1 100644 --- a/test/lish/does_not_include_pubspec_overrides_file.dart +++ b/test/lish/does_not_include_pubspec_overrides_file.dart
@@ -31,7 +31,7 @@ test('Check if package doesn\'t include pubspec_overrides.yaml', () async { await servePackages(); - await d.credentialsFile(globalServer, 'access token').create(); + await d.credentialsFile(globalServer, 'access-token').create(); var pub = await startPublish(globalServer); await confirmPublish(pub);
diff --git a/test/lish/force_publishes_if_tests_are_no_warnings_or_errors_test.dart b/test/lish/force_publishes_if_tests_are_no_warnings_or_errors_test.dart index c287c31..882fbf0 100644 --- a/test/lish/force_publishes_if_tests_are_no_warnings_or_errors_test.dart +++ b/test/lish/force_publishes_if_tests_are_no_warnings_or_errors_test.dart
@@ -16,7 +16,7 @@ test('--force publishes if there are no warnings or errors', () async { await servePackages(); await d.validPackage.create(); - await d.credentialsFile(globalServer, 'access token').create(); + await d.credentialsFile(globalServer, 'access-token').create(); var pub = await startPublish(globalServer, args: ['--force']); handleUploadForm(globalServer);
diff --git a/test/lish/force_publishes_if_there_are_warnings_test.dart b/test/lish/force_publishes_if_there_are_warnings_test.dart index 62e8754..cfc4567 100644 --- a/test/lish/force_publishes_if_there_are_warnings_test.dart +++ b/test/lish/force_publishes_if_there_are_warnings_test.dart
@@ -27,7 +27,7 @@ (await servePackages()).serve('foo', '1.0.0'); - await d.credentialsFile(globalServer, 'access token').create(); + await d.credentialsFile(globalServer, 'access-token').create(); var pub = await startPublish(globalServer, args: ['--force']); handleUploadForm(globalServer);
diff --git a/test/lish/many_files_test.dart b/test/lish/many_files_test.dart index d3805d1..7d9940e 100644 --- a/test/lish/many_files_test.dart +++ b/test/lish/many_files_test.dart
@@ -40,7 +40,7 @@ ], ).create(); await servePackages(); - await d.credentialsFile(globalServer, 'access token').create(); + await d.credentialsFile(globalServer, 'access-token').create(); var pub = await startPublish(globalServer); pub.stdin.writeln('y'); handleUploadForm(globalServer); @@ -107,7 +107,7 @@ } await servePackages(); - await d.credentialsFile(globalServer, 'access token').create(); + await d.credentialsFile(globalServer, 'access-token').create(); var pub = await startPublish(globalServer); await confirmPublish(pub);
diff --git a/test/lish/package_creation_provides_a_malformed_error_test.dart b/test/lish/package_creation_provides_a_malformed_error_test.dart index cb18e56..491fb6e 100644 --- a/test/lish/package_creation_provides_a_malformed_error_test.dart +++ b/test/lish/package_creation_provides_a_malformed_error_test.dart
@@ -15,7 +15,7 @@ test('package creation provides a malformed error', () async { await servePackages(); await d.validPackage.create(); - await d.credentialsFile(globalServer, 'access token').create(); + await d.credentialsFile(globalServer, 'access-token').create(); var pub = await startPublish(globalServer); await confirmPublish(pub);
diff --git a/test/lish/package_creation_provides_a_malformed_success_test.dart b/test/lish/package_creation_provides_a_malformed_success_test.dart index b65317c..3166285 100644 --- a/test/lish/package_creation_provides_a_malformed_success_test.dart +++ b/test/lish/package_creation_provides_a_malformed_success_test.dart
@@ -15,7 +15,7 @@ test('package creation provides a malformed success', () async { await servePackages(); await d.validPackage.create(); - await d.credentialsFile(globalServer, 'access token').create(); + await d.credentialsFile(globalServer, 'access-token').create(); var pub = await startPublish(globalServer); await confirmPublish(pub);
diff --git a/test/lish/package_creation_provides_an_error_test.dart b/test/lish/package_creation_provides_an_error_test.dart index c1d8bba..e7dbda4 100644 --- a/test/lish/package_creation_provides_an_error_test.dart +++ b/test/lish/package_creation_provides_an_error_test.dart
@@ -15,7 +15,7 @@ test('package creation provides an error', () async { await servePackages(); await d.validPackage.create(); - await d.credentialsFile(globalServer, 'access token').create(); + await d.credentialsFile(globalServer, 'access-token').create(); var pub = await startPublish(globalServer); await confirmPublish(pub);
diff --git a/test/lish/package_creation_provides_invalid_json_test.dart b/test/lish/package_creation_provides_invalid_json_test.dart index 124e01a..39c8e45 100644 --- a/test/lish/package_creation_provides_invalid_json_test.dart +++ b/test/lish/package_creation_provides_invalid_json_test.dart
@@ -13,7 +13,7 @@ test('package creation provides invalid JSON', () async { await servePackages(); await d.validPackage.create(); - await d.credentialsFile(globalServer, 'access token').create(); + await d.credentialsFile(globalServer, 'access-token').create(); var pub = await startPublish(globalServer); await confirmPublish(pub);
diff --git a/test/lish/package_validation_has_a_warning_and_continues_test.dart b/test/lish/package_validation_has_a_warning_and_continues_test.dart index 5355434..a5c083b 100644 --- a/test/lish/package_validation_has_a_warning_and_continues_test.dart +++ b/test/lish/package_validation_has_a_warning_and_continues_test.dart
@@ -22,7 +22,7 @@ File(d.path(p.join(appPath, 'README.md'))).deleteSync(); await servePackages(); - await d.credentialsFile(globalServer, 'access token').create(); + await d.credentialsFile(globalServer, 'access-token').create(); var pub = await startPublish(globalServer); expect(pub.stdout, emitsThrough(startsWith('Package has 1 warning.'))); pub.stdin.writeln('y');
diff --git a/test/lish/upload_form_fields_has_a_non_string_value_test.dart b/test/lish/upload_form_fields_has_a_non_string_value_test.dart index 8758bca..7793863 100644 --- a/test/lish/upload_form_fields_has_a_non_string_value_test.dart +++ b/test/lish/upload_form_fields_has_a_non_string_value_test.dart
@@ -14,7 +14,7 @@ test('upload form fields has a non-string value', () async { await servePackages(); await d.validPackage.create(); - await d.credentialsFile(globalServer, 'access token').create(); + await d.credentialsFile(globalServer, 'access-token').create(); var pub = await startPublish(globalServer); await confirmPublish(pub);
diff --git a/test/lish/upload_form_fields_is_not_a_map_test.dart b/test/lish/upload_form_fields_is_not_a_map_test.dart index dc41511..d0efb0d 100644 --- a/test/lish/upload_form_fields_is_not_a_map_test.dart +++ b/test/lish/upload_form_fields_is_not_a_map_test.dart
@@ -14,7 +14,7 @@ test('upload form fields is not a map', () async { await servePackages(); await d.validPackage.create(); - await d.credentialsFile(globalServer, 'access token').create(); + await d.credentialsFile(globalServer, 'access-token').create(); var pub = await startPublish(globalServer); await confirmPublish(pub);
diff --git a/test/lish/upload_form_is_missing_fields_test.dart b/test/lish/upload_form_is_missing_fields_test.dart index e909c0a..fc494ca 100644 --- a/test/lish/upload_form_is_missing_fields_test.dart +++ b/test/lish/upload_form_is_missing_fields_test.dart
@@ -14,7 +14,7 @@ test('upload form is missing fields', () async { await servePackages(); await d.validPackage.create(); - await d.credentialsFile(globalServer, 'access token').create(); + await d.credentialsFile(globalServer, 'access-token').create(); var pub = await startPublish(globalServer); await confirmPublish(pub);
diff --git a/test/lish/upload_form_is_missing_url_test.dart b/test/lish/upload_form_is_missing_url_test.dart index 418813f..e4f0291 100644 --- a/test/lish/upload_form_is_missing_url_test.dart +++ b/test/lish/upload_form_is_missing_url_test.dart
@@ -14,7 +14,7 @@ test('upload form is missing url', () async { await servePackages(); await d.validPackage.create(); - await d.credentialsFile(globalServer, 'access token').create(); + await d.credentialsFile(globalServer, 'access-token').create(); var pub = await startPublish(globalServer); await confirmPublish(pub);
diff --git a/test/lish/upload_form_provides_an_error_test.dart b/test/lish/upload_form_provides_an_error_test.dart index 048ca17..2eacb24 100644 --- a/test/lish/upload_form_provides_an_error_test.dart +++ b/test/lish/upload_form_provides_an_error_test.dart
@@ -14,7 +14,7 @@ test('upload form provides an error', () async { await servePackages(); await d.validPackage.create(); - await d.credentialsFile(globalServer, 'access token').create(); + await d.credentialsFile(globalServer, 'access-token').create(); var pub = await startPublish(globalServer); await confirmPublish(pub);
diff --git a/test/lish/upload_form_provides_invalid_json_test.dart b/test/lish/upload_form_provides_invalid_json_test.dart index 03f1551..14862bd 100644 --- a/test/lish/upload_form_provides_invalid_json_test.dart +++ b/test/lish/upload_form_provides_invalid_json_test.dart
@@ -13,7 +13,7 @@ await servePackages(); await d.validPackage.create(); await servePackages(); - await d.credentialsFile(globalServer, 'access token').create(); + await d.credentialsFile(globalServer, 'access-token').create(); var pub = await startPublish(globalServer); await confirmPublish(pub);
diff --git a/test/lish/upload_form_url_is_not_a_string_test.dart b/test/lish/upload_form_url_is_not_a_string_test.dart index b37d24f..45e9aa8 100644 --- a/test/lish/upload_form_url_is_not_a_string_test.dart +++ b/test/lish/upload_form_url_is_not_a_string_test.dart
@@ -14,7 +14,7 @@ test('upload form url is not a string', () async { await servePackages(); await d.validPackage.create(); - await d.credentialsFile(globalServer, 'access token').create(); + await d.credentialsFile(globalServer, 'access-token').create(); var pub = await startPublish(globalServer); await confirmPublish(pub);
diff --git a/test/lish/utils.dart b/test/lish/utils.dart index 03766a4..10d21e5 100644 --- a/test/lish/utils.dart +++ b/test/lish/utils.dart
@@ -13,7 +13,7 @@ server.expect('GET', '$path/api/packages/versions/new', (request) { expect( request.headers, - containsPair('authorization', 'Bearer access token'), + containsPair('authorization', 'Bearer access-token'), ); body ??= {
diff --git a/test/oauth2/logout_test.dart b/test/oauth2/logout_test.dart index f5c8619..6c835a9 100644 --- a/test/oauth2/logout_test.dart +++ b/test/oauth2/logout_test.dart
@@ -13,7 +13,7 @@ await d .credentialsFile( globalServer, - 'access token', + 'access-token', refreshToken: 'refresh token', expiration: DateTime.now().add(Duration(hours: 1)), ) @@ -31,7 +31,7 @@ await d .credentialsFile( globalServer, - 'access token', + 'access-token', refreshToken: 'refresh token', expiration: DateTime.now().add(Duration(hours: 1)), ) @@ -40,7 +40,7 @@ await d .legacyCredentialsFile( globalServer, - 'access token', + 'access-token', refreshToken: 'refresh token', expiration: DateTime.now().add(Duration(hours: 1)), )
diff --git a/test/oauth2/utils.dart b/test/oauth2/utils.dart index f7043a0..05636e2 100644 --- a/test/oauth2/utils.dart +++ b/test/oauth2/utils.dart
@@ -16,7 +16,7 @@ Future authorizePub( TestProcess pub, PackageServer server, [ - String accessToken = 'access token', + String accessToken = 'access-token', ]) async { await expectLater( pub.stdout,
diff --git a/test/oauth2/with_a_pre_existing_credentials_does_not_authenticate_test.dart b/test/oauth2/with_a_pre_existing_credentials_does_not_authenticate_test.dart index 3c22994..516204c 100644 --- a/test/oauth2/with_a_pre_existing_credentials_does_not_authenticate_test.dart +++ b/test/oauth2/with_a_pre_existing_credentials_does_not_authenticate_test.dart
@@ -12,7 +12,7 @@ await d.validPackage.create(); await servePackages(); - await d.credentialsFile(globalServer, 'access token').create(); + await d.credentialsFile(globalServer, 'access-token').create(); var pub = await startPublish(globalServer); await confirmPublish(pub);
diff --git a/test/oauth2/with_a_server_rejected_refresh_token_authenticates_again_test.dart b/test/oauth2/with_a_server_rejected_refresh_token_authenticates_again_test.dart index 7e38887..2237814 100644 --- a/test/oauth2/with_a_server_rejected_refresh_token_authenticates_again_test.dart +++ b/test/oauth2/with_a_server_rejected_refresh_token_authenticates_again_test.dart
@@ -23,7 +23,7 @@ await d .credentialsFile( globalServer, - 'access token', + 'access-token', refreshToken: 'bad refresh token', expiration: DateTime.now().subtract(Duration(hours: 1)), )
diff --git a/test/oauth2/with_an_expired_credentials_refreshes_and_saves_test.dart b/test/oauth2/with_an_expired_credentials_refreshes_and_saves_test.dart index c4a54e1..bca9feb 100644 --- a/test/oauth2/with_an_expired_credentials_refreshes_and_saves_test.dart +++ b/test/oauth2/with_an_expired_credentials_refreshes_and_saves_test.dart
@@ -20,7 +20,7 @@ await d .credentialsFile( globalServer, - 'access token', + 'access-token', refreshToken: 'refresh token', expiration: DateTime.now().subtract(Duration(hours: 1)), )
diff --git a/test/oauth2/with_an_expired_credentials_without_a_refresh_token_authenticates_again_test.dart b/test/oauth2/with_an_expired_credentials_without_a_refresh_token_authenticates_again_test.dart index ac22d7f..b21b496 100644 --- a/test/oauth2/with_an_expired_credentials_without_a_refresh_token_authenticates_again_test.dart +++ b/test/oauth2/with_an_expired_credentials_without_a_refresh_token_authenticates_again_test.dart
@@ -19,7 +19,7 @@ await d .credentialsFile( globalServer, - 'access token', + 'access-token', expiration: DateTime.now().subtract(Duration(hours: 1)), ) .create();
diff --git a/test/oauth2/with_no_credentials_authenticates_and_saves_credentials_test.dart b/test/oauth2/with_no_credentials_authenticates_and_saves_credentials_test.dart index c4d61ed..abe365f 100644 --- a/test/oauth2/with_no_credentials_authenticates_and_saves_credentials_test.dart +++ b/test/oauth2/with_no_credentials_authenticates_and_saves_credentials_test.dart
@@ -32,6 +32,6 @@ // do so rather than killing it so it'll write out the credentials file. await pub.shouldExit(1); - await d.credentialsFile(globalServer, 'access token').validate(); + await d.credentialsFile(globalServer, 'access-token').validate(); }); }
diff --git a/test/oauth2/with_server_rejected_credentials_authenticates_again_test.dart b/test/oauth2/with_server_rejected_credentials_authenticates_again_test.dart index 03468cf..c4b8d5b 100644 --- a/test/oauth2/with_server_rejected_credentials_authenticates_again_test.dart +++ b/test/oauth2/with_server_rejected_credentials_authenticates_again_test.dart
@@ -16,7 +16,7 @@ 'credentials.json', () async { await d.validPackage.create(); await servePackages(); - await d.credentialsFile(globalServer, 'access token').create(); + await d.credentialsFile(globalServer, 'access-token').create(); var pub = await startPublish(globalServer); await confirmPublish(pub);
diff --git a/test/token/add_token_test.dart b/test/token/add_token_test.dart index dd5d690..4321d90 100644 --- a/test/token/add_token_test.dart +++ b/test/token/add_token_test.dart
@@ -129,6 +129,19 @@ await d.dir(configPath, [d.nothing('pub-tokens.json')]).validate(); }); + test('with invalid token returns error', () async { + await d.dir(configPath).create(); + + await runPub( + args: ['token', 'add', 'https://pub.dev'], + error: contains('The entered token is not a valid Bearer token.'), + input: ['auth-token@'], // '@' is not allowed in bearer tokens + exitCode: exit_codes.DATA, + ); + + await d.dir(configPath, [d.nothing('pub-tokens.json')]).validate(); + }); + test('with non-secure server url returns error', () async { await d.dir(configPath).create(); await runPub(
diff --git a/test/token/error_message_test.dart b/test/token/error_message_test.dart index 0ccce60..5ed36dc 100644 --- a/test/token/error_message_test.dart +++ b/test/token/error_message_test.dart
@@ -34,7 +34,7 @@ await d.tokensFile({ 'version': 1, 'hosted': [ - {'url': globalServer.url, 'token': 'access token'}, + {'url': globalServer.url, 'token': 'access-token'}, ] }).create(); });
diff --git a/test/token/token_authentication_test.dart b/test/token/token_authentication_test.dart index d0b89c9..7bd74f1 100644 --- a/test/token/token_authentication_test.dart +++ b/test/token/token_authentication_test.dart
@@ -2,6 +2,7 @@ // for details. All rights reserved. Use of this source code is governed by a // BSD-style license that can be found in the LICENSE file. +import 'package:pub/src/exit_codes.dart' as exit_codes; import 'package:test/test.dart'; import '../descriptor.dart' as d; @@ -21,7 +22,7 @@ var pub = await startPublish( globalServer, overrideDefaultHostedServer: false, - environment: {'TOKEN': 'access token'}, + environment: {'TOKEN': 'access-token'}, ); await confirmPublish(pub); @@ -30,13 +31,60 @@ await pub.shouldExit(1); }); + test('with a invalid environment token fails with error', () async { + await servePackages(); + await d.validPackage.create(); + await d.tokensFile({ + 'version': 1, + 'hosted': [ + {'url': globalServer.url, 'env': 'TOKEN'}, + ] + }).create(); + await runPub( + args: ['publish'], + environment: { + 'TOKEN': 'access-token@' // '@' is not allowed in bearer tokens + }, + error: contains( + 'Credential token for ${globalServer.url} is not a valid Bearer token.', + ), + exitCode: exit_codes.DATA, + ); + }); + + test('with a pre existing invalid opaque token fails with error', () async { + await servePackages(); + await d.validPackage.create(); + await d.tokensFile({ + 'version': 1, + 'hosted': [ + // Corrupted files can be created by earlier pub versions that did not + // validate, or by manual edits. + { + 'url': globalServer.url, + 'token': 'access-token@', // '@' is not allowed in bearer tokens + }, + ] + }).create(); + await runPub( + args: ['publish'], + environment: { + 'TOKEN': 'access-token@' // '@' is not allowed in bearer tokens + }, + error: contains( + 'Credential token for ${globalServer.url} is not a valid Bearer token.', + ), + exitCode: exit_codes.DATA, + ); + }); + test('with a pre existing opaque token authenticates', () async { await servePackages(); await d.validPackage.create(); await d.tokensFile({ 'version': 1, 'hosted': [ - {'url': globalServer.url, 'token': 'access token'}, + {'url': globalServer.url, 'token': 'access-token'}, ] }).create(); var pub = await startPublish(
diff --git a/test/token/when_receives_401_removes_token_test.dart b/test/token/when_receives_401_removes_token_test.dart index 6ab0700..9e4d187 100644 --- a/test/token/when_receives_401_removes_token_test.dart +++ b/test/token/when_receives_401_removes_token_test.dart
@@ -15,7 +15,7 @@ await d.tokensFile({ 'version': 1, 'hosted': [ - {'url': server.url, 'token': 'access token'}, + {'url': server.url, 'token': 'access-token'}, ] }).create(); var pub = await startPublish(server, overrideDefaultHostedServer: false);
diff --git a/test/token/when_receives_403_persists_saved_token_test.dart b/test/token/when_receives_403_persists_saved_token_test.dart index 3fef9a5..2141173 100644 --- a/test/token/when_receives_403_persists_saved_token_test.dart +++ b/test/token/when_receives_403_persists_saved_token_test.dart
@@ -15,7 +15,7 @@ await d.tokensFile({ 'version': 1, 'hosted': [ - {'url': server.url, 'token': 'access token'}, + {'url': server.url, 'token': 'access-token'}, ] }).create(); var pub = await startPublish(server, overrideDefaultHostedServer: false); @@ -30,7 +30,7 @@ await d.tokensFile({ 'version': 1, 'hosted': [ - {'url': server.url, 'token': 'access token'}, + {'url': server.url, 'token': 'access-token'}, ] }).validate(); });