Files
firebase-ios-sdk/FirebaseAppCheck/Sources/DebugProvider/FIRAppCheckDebugProvider.m
T
Maksym MalyhinandNick Cooke 302f91e1ed App Check: App Attest provider (#8133)
* App Attest provider: attestation sequence (#7971)

* App Attest provider: attestation sequence (#761)

* App Attest draft WIP

* FIRAppAttestProvider initializers

* ./scripts/style.sh

* FIRAppAttestProvider implementation draft

* Basic FIRAppAttestProviderTests and fixes

* style

* testGetTokenWhenAppAttestIsNotSupported

* More FIRAppAttestProviderTests

* Cleanup

* Remove unused file

* Availability annotations on DCAppAttestService category.

* Guard FIRAppAttestProvider with #if TARGET_OS_IOS

* Formatting

* Fix SPM

* app_check.yaml: Add diagnostics SPM builds

* fix yaml

* Fix Firebase-Package scheme bad merge

* Fix typo

* FIRAppAttestProvider: hide default init

* FIRAppAttestKeyIDStorage: methods placeholders

* Comments

* Fix updated block definition

* Implement app attest key ID storage (#8014)

* Implement FIRAppAttestKeyIDStorage

* Add FIRAppAttestKeyIDStorageTests

* Review [Draft]

* Style

* Docs updates

* Docs updates 2

* Review [Draft] 2

* Improve tests

* Improve test readability

* Improve test readability 2

* App Check App Attest workflow updates: initial handshake (#8032)

* Handshake adjustments (WIP)

* Introduce FIRAppAttestProviderState

* WIP: calculate attestation state

* WIP: calculate attestation state 2

* formatting

* Comments and moving code around

* Fix init in tests

* Fix state calculation flow

* Cleanup state calculation and fix tests.

* Cleanup and fixes.

* Comments

* formatting

* Fix import

* Typo fixes and additional comments

* FIRAppAttestInitialHandshakeResponse API

* Cleanup state calculation using FBLPromiseAwait

* Cleanup

* style

* FIRAppAttestArtifactStorage implementation and tests (#8041)

* Update comments

* FIRAppAttestArtifactStorage implementation and tests

* Fix init

* API docs

* Clean up storage in tests

* Comments

* Disable Keychain dependent tests for SPM

* Implement App Attest `getRandomChallenge` (#8033)

* Initial implementation

* Parse response body for challenge and stub test cases

* Review [Draft]

* Avoid encoding challenge again

* Add tests

* Revert "Avoid encoding challenge again" and add TODO

This reverts commit 69eb00dfe2.

* Document tests; Add test

* Tests: Add URL validation check

* Review

* Define Exchange AppAttest Assertion for FAC token API (#8058)

* App Check App Attest: attestation request (#8059)

* App Attest provider API integration WIP

* update tests

* Draft attestation response parsing

* Attestation request draft

* style

* AppAttest Attestation API tests draft

* Error cases tests

* style

* Cleanup and API docs

* Merge fix

* Fix OCMock imports

* Fix nullability modifier

* Formatting

* comments

* App Check App Attest initial handshake adjustments (#8067)

* calculatre sha256 of random challenge for attestation

* Test app adjustments

* cleanup

* use trailing closures in the test app

* Implement API for ExchangeAppAttestAssertionRequest endpoint (#8065)

* Implement assertion exchange

* Tweak existing tests

* Add tests

* Rename JSON to better match gRPC  message

* Add HTTPBody helper

* Review

* Review 2

* Review 3

* App Check App Attest assertion flow (#8083)

* App Attest assertion workflow draft

* send request

* assertion flow tests

* style

* App Check: store App Attest artifact per key ID (#8097)

* Update artifact storage API and tests

* Artifact storage implementation update

* Save artifact for a key ID

* Style

* typos

* App Check: prevent concurrent token requests (#8117)

* App Attest multiple get token method invocation tests

* Ensure a single App Attest handshake sequence at the time

* FIRAppCheckTests: get token request merging tests

* FIRAppCheck: Ensure a single get token operation at the time

* formatting

* Test new request after merged requests

* Release finished operation promise

* Style

* Typos

* typo

* Request merging tests for error cases

* formatting

* Changelog

* App Check App Attest: handle attestation rejection (#8170)

* Remove/update outdated TODOs

* [WIP] Attestation rejection handling draft

* style

* retry tests draft

* reset key ID before retry

* Reset attestation

* test error and fixes

* style

* More details in the name

* Some debug logging

* style

* Use specific codes for log messages

* style

* Add FIRAppAttestProvider.h the umbrella header

Co-authored-by: Nick Cooke <36927374+ncooke3@users.noreply.github.com>
2021-06-01 10:47:57 -04:00

131 lines
4.7 KiB
Objective-C

/*
* Copyright 2020 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#import "FirebaseAppCheck/Sources/Public/FirebaseAppCheck/FIRAppCheckDebugProvider.h"
#if __has_include(<FBLPromises/FBLPromises.h>)
#import <FBLPromises/FBLPromises.h>
#else
#import "FBLPromises.h"
#endif
#import "FirebaseAppCheck/Sources/Core/APIService/FIRAppCheckAPIService.h"
#import "FirebaseAppCheck/Sources/Core/FIRAppCheckLogger.h"
#import "FirebaseAppCheck/Sources/Core/FIRAppCheckValidator.h"
#import "FirebaseAppCheck/Sources/DebugProvider/API/FIRAppCheckDebugProviderAPIService.h"
#import "FirebaseAppCheck/Sources/Public/FirebaseAppCheck/FIRAppCheckToken.h"
#import "FirebaseCore/Sources/Private/FirebaseCoreInternal.h"
NS_ASSUME_NONNULL_BEGIN
static NSString *const kDebugTokenEnvKey = @"FIRAAppCheckDebugToken";
static NSString *const kDebugTokenUserDefaultsKey = @"FIRAAppCheckDebugToken";
@interface FIRAppCheckDebugProvider ()
@property(nonatomic, readonly) id<FIRAppCheckDebugProviderAPIServiceProtocol> APIService;
@end
@implementation FIRAppCheckDebugProvider
- (instancetype)initWithAPIService:(id<FIRAppCheckDebugProviderAPIServiceProtocol>)APIService {
self = [super init];
if (self) {
_APIService = APIService;
}
return self;
}
- (nullable instancetype)initWithApp:(FIRApp *)app {
NSArray<NSString *> *missingOptionsFields =
[FIRAppCheckValidator tokenExchangeMissingFieldsInOptions:app.options];
if (missingOptionsFields.count > 0) {
FIRLogError(kFIRLoggerAppCheck, kFIRLoggerAppCheckMessageDebugProviderIncompleteFIROptions,
@"Cannot instantiate `FIRAppCheckDebugProvider` for app: %@. The following "
@"`FirebaseOptions` fields are missing: %@",
app.name, [missingOptionsFields componentsJoinedByString:@", "]);
return nil;
}
NSURLSession *URLSession = [NSURLSession
sessionWithConfiguration:[NSURLSessionConfiguration ephemeralSessionConfiguration]];
FIRAppCheckAPIService *APIService =
[[FIRAppCheckAPIService alloc] initWithURLSession:URLSession
APIKey:app.options.APIKey
projectID:app.options.projectID
appID:app.options.googleAppID];
FIRAppCheckDebugProviderAPIService *debugAPIService =
[[FIRAppCheckDebugProviderAPIService alloc] initWithAPIService:APIService
projectID:app.options.projectID
appID:app.options.googleAppID];
return [self initWithAPIService:debugAPIService];
}
- (NSString *)currentDebugToken {
NSString *envVariableValue = [[NSProcessInfo processInfo] environment][kDebugTokenEnvKey];
if (envVariableValue.length > 0) {
return envVariableValue;
} else {
return [self localDebugToken];
}
}
- (NSString *)localDebugToken {
return [self storedDebugToken] ?: [self generateAndStoreDebugToken];
}
- (nullable NSString *)storedDebugToken {
return [[NSUserDefaults standardUserDefaults] stringForKey:kDebugTokenUserDefaultsKey];
}
- (void)storeDebugToken:(nullable NSString *)token {
[[NSUserDefaults standardUserDefaults] setObject:token forKey:kDebugTokenUserDefaultsKey];
}
- (NSString *)generateAndStoreDebugToken {
NSString *token = [NSUUID UUID].UUIDString;
[self storeDebugToken:token];
return token;
}
#pragma mark - FIRAppCheckProvider
- (void)getTokenWithCompletion:(void (^)(FIRAppCheckToken *_Nullable token,
NSError *_Nullable error))handler {
[FBLPromise do:^NSString * {
return [self currentDebugToken];
}]
.then(^FBLPromise<FIRAppCheckToken *> *(NSString *debugToken) {
return [self.APIService appCheckTokenWithDebugToken:debugToken];
})
.then(^id(FIRAppCheckToken *appCheckToken) {
handler(appCheckToken, nil);
return nil;
})
.catch(^void(NSError *error) {
FIRAppCheckDebugLog(kFIRLoggerAppCheckMessageDebugProviderFailedExchange,
@"Failed to exchange debug token to app check token: %@", error);
handler(nil, error);
});
}
@end
NS_ASSUME_NONNULL_END