@bifold/react-native-attestation 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (32) hide show
  1. package/LICENSE +202 -0
  2. package/README.md +39 -0
  3. package/android/build.gradle +123 -0
  4. package/android/gradle.properties +5 -0
  5. package/android/src/main/AndroidManifest.xml +3 -0
  6. package/android/src/main/AndroidManifestNew.xml +2 -0
  7. package/android/src/main/java/com/attestation/AttestationModule.kt +89 -0
  8. package/android/src/main/java/com/attestation/AttestationPackage.kt +35 -0
  9. package/android/src/newarch/AttestationSpec.kt +7 -0
  10. package/android/src/oldarch/AttestationSpec.kt +12 -0
  11. package/build/commonjs/NativeAttestation.js +9 -0
  12. package/build/commonjs/NativeAttestation.js.map +1 -0
  13. package/build/commonjs/index.js +72 -0
  14. package/build/commonjs/index.js.map +1 -0
  15. package/build/module/NativeAttestation.js +3 -0
  16. package/build/module/NativeAttestation.js.map +1 -0
  17. package/build/module/index.js +59 -0
  18. package/build/module/index.js.map +1 -0
  19. package/build/typescript/NativeAttestation.d.ts +12 -0
  20. package/build/typescript/NativeAttestation.d.ts.map +1 -0
  21. package/build/typescript/__tests__/index.test.d.ts +1 -0
  22. package/build/typescript/__tests__/index.test.d.ts.map +1 -0
  23. package/build/typescript/index.d.ts +8 -0
  24. package/build/typescript/index.d.ts.map +1 -0
  25. package/ios/Attestation.h +12 -0
  26. package/ios/Attestation.mm +280 -0
  27. package/ios/Attestation.xcodeproj/project.pbxproj +276 -0
  28. package/package.json +116 -0
  29. package/react-native-attestation.podspec +44 -0
  30. package/src/NativeAttestation.ts +13 -0
  31. package/src/__tests__/index.test.tsx +1 -0
  32. package/src/index.ts +95 -0
@@ -0,0 +1,59 @@
1
+ import { NativeModules, Platform } from 'react-native';
2
+ import { Buffer } from 'buffer';
3
+ import NativeAttestationSpec from './NativeAttestation';
4
+ const LINKING_ERROR = `The package 'react-native-attestation' doesn't seem to be linked. Make sure: \n\n` + Platform.select({
5
+ ios: "- You have run 'pod install'\n",
6
+ default: ''
7
+ }) + '- You rebuilt the app after installing the package\n' + '- You are not using Expo Go\n';
8
+
9
+ // @ts-expect-error global.__turboModuleProxy is a global variable injected by TurboModuleProxy
10
+ const isTurboModuleEnabled = global.__turboModuleProxy != null;
11
+ const AttestationModule = isTurboModuleEnabled ? NativeAttestationSpec : NativeModules.Attestation;
12
+ const Attestation = AttestationModule ? AttestationModule : new Proxy({}, {
13
+ get() {
14
+ throw new Error(LINKING_ERROR);
15
+ }
16
+ });
17
+
18
+ // TODO: Make available from Android.
19
+ export const sha256 = async stringToHash => {
20
+ if (Platform.OS !== 'ios') {
21
+ throw new Error('sha256 is only available on iOS');
22
+ }
23
+ const bytes = await Attestation.sha256(stringToHash);
24
+ return Buffer.from(bytes);
25
+ };
26
+ export const generateKey = async (cache = false) => {
27
+ if (Platform.OS !== 'ios') {
28
+ throw new Error('generateKey is only available on iOS');
29
+ }
30
+ return Attestation.generateKey(cache);
31
+ };
32
+ export const appleKeyAttestation = async (keyId, challenge) => {
33
+ if (Platform.OS !== 'ios') {
34
+ throw new Error('appleKeyAttestation is only available on iOS');
35
+ }
36
+ const bytes = await Attestation.appleKeyAttestation(keyId, challenge);
37
+ return Buffer.from(bytes);
38
+ };
39
+ export const appleAttestation = async (keyId, challenge) => {
40
+ if (Platform.OS !== 'ios') {
41
+ throw new Error('appleAttestation is only available on iOS');
42
+ }
43
+ const bytes = await Attestation.appleAttestation(keyId, challenge);
44
+ return Buffer.from(bytes);
45
+ };
46
+ export const googleAttestation = async nonce => {
47
+ if (Platform.OS !== 'android') {
48
+ throw new Error('googleAttestation is only available on Android');
49
+ }
50
+ const token = await Attestation.googleAttestation(nonce);
51
+ return token;
52
+ };
53
+ export const isPlayIntegrityAvailable = async () => {
54
+ if (Platform.OS !== 'android') {
55
+ throw new Error('isPlayIntegrityAvailable is only available on Android');
56
+ }
57
+ return Attestation.isPlayIntegrityAvailable();
58
+ };
59
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":["NativeModules","Platform","Buffer","NativeAttestationSpec","LINKING_ERROR","select","ios","default","isTurboModuleEnabled","global","__turboModuleProxy","AttestationModule","Attestation","Proxy","get","Error","sha256","stringToHash","OS","bytes","from","generateKey","cache","appleKeyAttestation","keyId","challenge","appleAttestation","googleAttestation","nonce","token","isPlayIntegrityAvailable"],"sourceRoot":"../../src","sources":["index.ts"],"mappings":"AAAA,SAASA,aAAa,EAAEC,QAAQ,QAAQ,cAAc;AACtD,SAASC,MAAM,QAAQ,QAAQ;AAE/B,OAAOC,qBAAqB,MAAM,qBAAqB;AAEvD,MAAMC,aAAa,GACjB,mFAAmF,GACnFH,QAAQ,CAACI,MAAM,CAAC;EAAEC,GAAG,EAAE,gCAAgC;EAAEC,OAAO,EAAE;AAAG,CAAC,CAAC,GACvE,sDAAsD,GACtD,+BAA+B;;AAEjC;AACA,MAAMC,oBAAoB,GAAGC,MAAM,CAACC,kBAAkB,IAAI,IAAI;AAE9D,MAAMC,iBAAiB,GAAGH,oBAAoB,GAC1CL,qBAAqB,GACrBH,aAAa,CAACY,WAAW;AAE7B,MAAMA,WAAW,GAAGD,iBAAiB,GACjCA,iBAAiB,GACjB,IAAIE,KAAK,CACP,CAAC,CAAC,EACF;EACEC,GAAGA,CAAA,EAAG;IACJ,MAAM,IAAIC,KAAK,CAACX,aAAa,CAAC;EAChC;AACF,CACF,CAAC;;AAEL;AACA,OAAO,MAAMY,MAAM,GAAG,MAAOC,YAAoB,IAAsB;EACrE,IAAIhB,QAAQ,CAACiB,EAAE,KAAK,KAAK,EAAE;IACzB,MAAM,IAAIH,KAAK,CAAC,iCAAiC,CAAC;EACpD;EAEA,MAAMI,KAAiB,GAAG,MAAMP,WAAW,CAACI,MAAM,CAACC,YAAY,CAAC;EAChE,OAAOf,MAAM,CAACkB,IAAI,CAACD,KAAK,CAAC;AAC3B,CAAC;AAED,OAAO,MAAME,WAAW,GAAG,MAAAA,CAAOC,KAAc,GAAG,KAAK,KAAsB;EAC5E,IAAIrB,QAAQ,CAACiB,EAAE,KAAK,KAAK,EAAE;IACzB,MAAM,IAAIH,KAAK,CAAC,sCAAsC,CAAC;EACzD;EAEA,OAAOH,WAAW,CAACS,WAAW,CAACC,KAAK,CAAC;AACvC,CAAC;AAED,OAAO,MAAMC,mBAAmB,GAAG,MAAAA,CACjCC,KAAa,EACbC,SAAiB,KACG;EACpB,IAAIxB,QAAQ,CAACiB,EAAE,KAAK,KAAK,EAAE;IACzB,MAAM,IAAIH,KAAK,CAAC,8CAA8C,CAAC;EACjE;EAEA,MAAMI,KAAiB,GAAG,MAAMP,WAAW,CAACW,mBAAmB,CAC7DC,KAAK,EACLC,SACF,CAAC;EAED,OAAOvB,MAAM,CAACkB,IAAI,CAACD,KAAK,CAAC;AAC3B,CAAC;AAED,OAAO,MAAMO,gBAAgB,GAAG,MAAAA,CAC9BF,KAAa,EACbC,SAAiB,KACG;EACpB,IAAIxB,QAAQ,CAACiB,EAAE,KAAK,KAAK,EAAE;IACzB,MAAM,IAAIH,KAAK,CAAC,2CAA2C,CAAC;EAC9D;EAEA,MAAMI,KAAiB,GAAG,MAAMP,WAAW,CAACc,gBAAgB,CAC1DF,KAAK,EACLC,SACF,CAAC;EAED,OAAOvB,MAAM,CAACkB,IAAI,CAACD,KAAK,CAAC;AAC3B,CAAC;AAED,OAAO,MAAMQ,iBAAiB,GAAG,MAAOC,KAAa,IAAsB;EACzE,IAAI3B,QAAQ,CAACiB,EAAE,KAAK,SAAS,EAAE;IAC7B,MAAM,IAAIH,KAAK,CAAC,gDAAgD,CAAC;EACnE;EAEA,MAAMc,KAAa,GAAG,MAAMjB,WAAW,CAACe,iBAAiB,CAACC,KAAK,CAAC;EAChE,OAAOC,KAAK;AACd,CAAC;AAED,OAAO,MAAMC,wBAAwB,GAAG,MAAAA,CAAA,KAA8B;EACpE,IAAI7B,QAAQ,CAACiB,EAAE,KAAK,SAAS,EAAE;IAC7B,MAAM,IAAIH,KAAK,CAAC,uDAAuD,CAAC;EAC1E;EAEA,OAAOH,WAAW,CAACkB,wBAAwB,CAAC,CAAC;AAC/C,CAAC","ignoreList":[]}
@@ -0,0 +1,12 @@
1
+ import type { TurboModule } from 'react-native';
2
+ export interface Spec extends TurboModule {
3
+ generateKey(cache: boolean): Promise<string>;
4
+ sha256(stringToHash: string): Promise<Buffer>;
5
+ appleAttestation(keyId: string, challenge: string): Promise<Buffer>;
6
+ appleKeyAttestation(keyId: string, challenge: string): Promise<Buffer>;
7
+ isPlayIntegrityAvailable(): Promise<boolean>;
8
+ googleAttestation(nonce: string): Promise<string>;
9
+ }
10
+ declare const _default: Spec;
11
+ export default _default;
12
+ //# sourceMappingURL=NativeAttestation.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"NativeAttestation.d.ts","sourceRoot":"","sources":["../../src/NativeAttestation.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAGhD,MAAM,WAAW,IAAK,SAAQ,WAAW;IACvC,WAAW,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IAC7C,MAAM,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IAC9C,gBAAgB,CAAC,KAAK,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IACpE,mBAAmB,CAAC,KAAK,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IACvE,wBAAwB,IAAI,OAAO,CAAC,OAAO,CAAC,CAAC;IAC7C,iBAAiB,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;CACnD;;AAED,wBAAqE"}
@@ -0,0 +1 @@
1
+ //# sourceMappingURL=index.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.test.d.ts","sourceRoot":"","sources":["../../../src/__tests__/index.test.tsx"],"names":[],"mappings":""}
@@ -0,0 +1,8 @@
1
+ import { Buffer } from 'buffer';
2
+ export declare const sha256: (stringToHash: string) => Promise<Buffer>;
3
+ export declare const generateKey: (cache?: boolean) => Promise<string>;
4
+ export declare const appleKeyAttestation: (keyId: string, challenge: string) => Promise<Buffer>;
5
+ export declare const appleAttestation: (keyId: string, challenge: string) => Promise<Buffer>;
6
+ export declare const googleAttestation: (nonce: string) => Promise<string>;
7
+ export declare const isPlayIntegrityAvailable: () => Promise<boolean>;
8
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AA6BhC,eAAO,MAAM,MAAM,iBAAwB,MAAM,KAAG,OAAO,CAAC,MAAM,CAOjE,CAAC;AAEF,eAAO,MAAM,WAAW,WAAiB,OAAO,KAAW,OAAO,CAAC,MAAM,CAMxE,CAAC;AAEF,eAAO,MAAM,mBAAmB,UACvB,MAAM,aACF,MAAM,KAChB,OAAO,CAAC,MAAM,CAWhB,CAAC;AAEF,eAAO,MAAM,gBAAgB,UACpB,MAAM,aACF,MAAM,KAChB,OAAO,CAAC,MAAM,CAWhB,CAAC;AAEF,eAAO,MAAM,iBAAiB,UAAiB,MAAM,KAAG,OAAO,CAAC,MAAM,CAOrE,CAAC;AAEF,eAAO,MAAM,wBAAwB,QAAa,OAAO,CAAC,OAAO,CAMhE,CAAC"}
@@ -0,0 +1,12 @@
1
+
2
+ #ifdef RCT_NEW_ARCH_ENABLED
3
+ #import "RNAttestationSpec.h"
4
+
5
+ @interface Attestation : NSObject <NativeAttestationSpec>
6
+ #else
7
+ #import <React/RCTBridgeModule.h>
8
+
9
+ @interface Attestation : NSObject <RCTBridgeModule>
10
+ #endif
11
+
12
+ @end
@@ -0,0 +1,280 @@
1
+ #import "Attestation.h"
2
+ #import <DeviceCheck/DeviceCheck.h>
3
+ #import <CommonCrypto/CommonCrypto.h>
4
+ #import <Security/Security.h>
5
+
6
+ @implementation Attestation
7
+ RCT_EXPORT_MODULE()
8
+
9
+ NSString *KeychainServiceName = @"AriesAttestation";
10
+
11
+ NSString *keychainIdentifier2() {
12
+ NSString *bundleID = [[NSBundle mainBundle] bundleIdentifier];
13
+ NSString *concatenatedString = [bundleID stringByAppendingString:@".AttestationKey"];
14
+
15
+ return concatenatedString;
16
+ }
17
+
18
+ NSData *sha256Of(NSString *stringToBeHashed) {
19
+ NSData *data = [stringToBeHashed dataUsingEncoding:NSUTF8StringEncoding];
20
+ uint8_t hash[CC_SHA256_DIGEST_LENGTH];
21
+ CC_SHA256(data.bytes, (CC_LONG)data.length, hash);
22
+ NSData *hashData = [NSData dataWithBytes:hash length:CC_SHA256_DIGEST_LENGTH];
23
+
24
+ return hashData;
25
+ }
26
+
27
+ NSArray<NSNumber *> *dataToBytes(NSData *data) {
28
+ const uint8_t *bytes = (const uint8_t *)[data bytes];
29
+ NSMutableArray *array = [NSMutableArray arrayWithCapacity:data.length];
30
+ for (NSUInteger i = 0; i < data.length; i++) {
31
+ [array addObject:@(bytes[i])];
32
+ }
33
+
34
+ return [array copy];
35
+ }
36
+
37
+ BOOL saveStringToKeychain(NSString *string, NSString *identifier) {
38
+ NSData *stringAsData = [string dataUsingEncoding:NSUTF8StringEncoding];
39
+
40
+ NSDictionary *attributes = @{
41
+ (__bridge id)kSecClass: (__bridge id)kSecClassGenericPassword,
42
+ (__bridge id)kSecAttrService: KeychainServiceName,
43
+ (__bridge id)kSecAttrAccount: identifier,
44
+ (__bridge id)kSecValueData: stringAsData
45
+ };
46
+
47
+ OSStatus status = SecItemAdd((__bridge CFDictionaryRef)attributes, NULL);
48
+
49
+ return status == errSecSuccess;
50
+ }
51
+
52
+ NSString *stringFromKeychainWithIdentifier(NSString *identifier) {
53
+
54
+ NSDictionary *query = @{
55
+ (__bridge id)kSecClass: (__bridge id)kSecClassGenericPassword,
56
+ (__bridge id)kSecAttrService: KeychainServiceName,
57
+ (__bridge id)kSecAttrAccount: identifier,
58
+ (__bridge id)kSecReturnData: (__bridge id)kCFBooleanTrue,
59
+ (__bridge id)kSecMatchLimit: (__bridge id)kSecMatchLimitOne
60
+ };
61
+
62
+ CFTypeRef dataRef = NULL;
63
+ OSStatus status = SecItemCopyMatching((__bridge CFDictionaryRef)query, &dataRef);
64
+ if (status == errSecSuccess) {
65
+ NSData *data = (__bridge_transfer NSData *)dataRef;
66
+ return [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
67
+ } else {
68
+ return nil;
69
+ }
70
+ }
71
+
72
+ BOOL clearStoredKeyIfExists(NSString *identifier) {
73
+ NSDictionary *query = @{
74
+ (__bridge id)kSecClass: (__bridge id)kSecClassGenericPassword,
75
+ (__bridge id)kSecAttrService: identifier
76
+ };
77
+
78
+ // Delete the item from the Keychain.
79
+ OSStatus status = SecItemDelete((__bridge CFDictionaryRef)query);
80
+
81
+ if (status == errSecSuccess) {
82
+ NSLog(@"Item deleted successfully.");
83
+ return YES;
84
+ } else if (status == errSecItemNotFound) {
85
+ NSLog(@"Item not found in Keychain.");
86
+ return NO;
87
+ } else {
88
+ NSLog(@"Error deleting item from Keychain. Status code: %d", (int)status);
89
+ return NO;
90
+ }
91
+ }
92
+
93
+ NSError *errorWithReason(NSString *reason, NSInteger code) {
94
+ NSString *domain = [[NSBundle mainBundle] bundleIdentifier];
95
+ NSDictionary *userInfo = @{
96
+ NSLocalizedDescriptionKey: @"An error occurred.",
97
+ NSLocalizedFailureReasonErrorKey: reason,
98
+ };
99
+
100
+ return [NSError errorWithDomain:domain code:code userInfo:userInfo];
101
+ }
102
+
103
+ NSString *messageAttestationErrorCode(NSInteger code) {
104
+ NSString *result;
105
+
106
+ // See https://developer.apple.com/documentation/devicecheck/dcerror
107
+ // for a full list and description of errors.
108
+ switch (code) {
109
+ case 2: // DCErrorInvalidInput
110
+ // This may occur if the key is no longer valid or other
111
+ // unexpected input is provided.
112
+ result = @"The provided input is not formatted correctly.";
113
+ break;
114
+ case 3:
115
+ result = @"The provided key ID is invalid or the key is not found.";
116
+ break;
117
+ case 4:
118
+ result = @"The device is not eligible for App Attestation.";
119
+ break;
120
+ default:
121
+ result = @"Unable to generate attestation object.";
122
+ break;
123
+ }
124
+
125
+ return result;
126
+ }
127
+
128
+ DCAppAttestService *sharedService() {
129
+ NSString *version = [[UIDevice currentDevice] systemVersion];
130
+ if ([version compare:@"14.0" options:NSNumericSearch] != NSOrderedDescending) {
131
+ NSLog(@"iOS version is less than 14.0");
132
+ return nil;
133
+ }
134
+
135
+ DCAppAttestService *service = [DCAppAttestService sharedService];
136
+ if (service.isSupported) {
137
+ return service;
138
+ }
139
+
140
+ return nil;
141
+ }
142
+
143
+ // See // https://reactnative.dev/docs/native-modules-ios
144
+
145
+ RCT_EXPORT_METHOD(generateKey:(BOOL)cache
146
+ resolve:(RCTPromiseResolveBlock)resolve
147
+ reject:(RCTPromiseRejectBlock)reject)
148
+ {
149
+ NSString *keyId = nil;
150
+
151
+ DCAppAttestService *attestService = sharedService();
152
+ if (attestService == nil) {
153
+ NSString *message = @"The device is not eligible for App Attestation.";
154
+ reject(@"error", message, errorWithReason(message, 22));
155
+
156
+ return;
157
+ }
158
+
159
+ NSString *keychainIdentifier = keychainIdentifier2();
160
+
161
+ if (cache) {
162
+ keyId = stringFromKeychainWithIdentifier(keychainIdentifier);
163
+ } else {
164
+ clearStoredKeyIfExists(keychainIdentifier);
165
+ }
166
+
167
+ if (keyId != nil) {
168
+ NSLog(@"returning existing key...");
169
+ resolve(keyId);
170
+
171
+ return;
172
+ }
173
+
174
+ [attestService generateKeyWithCompletionHandler:^(NSString * _Nullable keyId, NSError * _Nullable error) {
175
+ if (error) {
176
+ NSLog(@"generateKeyWithCompletionHandler error %@", error);
177
+ reject(@"error", @"Unable to generate key.", errorWithReason(@"Unable to generate key.", 21));
178
+
179
+ return;
180
+ }
181
+
182
+ NSLog(@"saving key to KC = %@", keyId);
183
+
184
+ if (cache) {
185
+ saveStringToKeychain(keyId, keychainIdentifier);
186
+ }
187
+
188
+ resolve(keyId);
189
+ }];
190
+ }
191
+
192
+ RCT_EXPORT_METHOD(sha256:(NSString *)stringToBeHashed
193
+ resolve:(RCTPromiseResolveBlock)resolve
194
+ reject:(RCTPromiseRejectBlock)reject)
195
+ {
196
+ NSArray<NSNumber *> *result = [dataToBytes(sha256Of(stringToBeHashed)) copy];
197
+
198
+ resolve(result);
199
+ }
200
+
201
+ RCT_EXPORT_METHOD(appleKeyAttestation:(NSString *)keyId
202
+ challenge:(NSString *)challenge
203
+ resolve:(RCTPromiseResolveBlock)resolve
204
+ reject:(RCTPromiseRejectBlock)reject)
205
+ {
206
+ NSInteger InvalidKeyErrorCode = 3;
207
+ DCAppAttestService *attestService = sharedService();
208
+ if (attestService == nil) {
209
+ NSString *message = @"The device is not eligible for App Attestation.";
210
+ reject(@"error", message, errorWithReason(message, 22));
211
+
212
+ return;
213
+ }
214
+
215
+ NSData *hashData = sha256Of(challenge);
216
+
217
+ [attestService attestKey:keyId clientDataHash:hashData completionHandler:^(NSData * _Nullable attestationObject, NSError * _Nullable error) {
218
+
219
+ if (error) {
220
+ NSLog(@"attestKey error %@", error);
221
+ NSString *message = messageAttestationErrorCode(error.code);
222
+
223
+ if (error.code == InvalidKeyErrorCode) {
224
+ NSString *keychainIdentifier = keychainIdentifier2();
225
+ clearStoredKeyIfExists(keychainIdentifier);
226
+ }
227
+
228
+ reject(@"error", message, errorWithReason(message, error.code));
229
+ } else {
230
+ NSArray<NSNumber *> *result = dataToBytes(attestationObject);
231
+ resolve(result);
232
+ }
233
+ }];
234
+ }
235
+
236
+ RCT_EXPORT_METHOD(appleAttestation:(NSString *)keyId
237
+ challenge:(NSString *)challenge
238
+ resolve:(RCTPromiseResolveBlock)resolve
239
+ reject:(RCTPromiseRejectBlock)reject)
240
+ {
241
+ NSInteger InvalidKeyErrorCode = 3;
242
+ DCAppAttestService *attestService = sharedService();
243
+ if (attestService == nil) {
244
+ NSString *message = @"The device is not eligible for App Attestation.";
245
+ reject(@"error", message, errorWithReason(message, 22));
246
+
247
+ return;
248
+ }
249
+
250
+ NSData *hashData = sha256Of(challenge);
251
+
252
+ [attestService attestKey:keyId clientDataHash:hashData completionHandler:^(NSData * _Nullable attestationObject, NSError * _Nullable error) {
253
+
254
+ if (error) {
255
+ NSLog(@"appleAttestationAsBase64 error %@", error);
256
+ NSString *message = messageAttestationErrorCode(error.code);
257
+
258
+ if (error.code == InvalidKeyErrorCode) {
259
+ NSString *keychainIdentifier = keychainIdentifier2();
260
+ clearStoredKeyIfExists(keychainIdentifier);
261
+ }
262
+
263
+ reject(@"error", message, errorWithReason(message, error.code));
264
+ } else {
265
+ NSArray<NSNumber *> *result = dataToBytes(attestationObject);
266
+ resolve(result);
267
+ }
268
+ }];
269
+ }
270
+
271
+ // Don't compile this code when we build for the old architecture.
272
+ #ifdef RCT_NEW_ARCH_ENABLED
273
+ - (std::shared_ptr<facebook::react::TurboModule>)getTurboModule:
274
+ (const facebook::react::ObjCTurboModule::InitParams &)params
275
+ {
276
+ return std::make_shared<facebook::react::NativeAttestationSpecJSI>(params);
277
+ }
278
+ #endif
279
+
280
+ @end
@@ -0,0 +1,276 @@
1
+ // !$*UTF8*$!
2
+ {
3
+ archiveVersion = 1;
4
+ classes = {
5
+ };
6
+ objectVersion = 46;
7
+ objects = {
8
+
9
+ /* Begin PBXBuildFile section */
10
+ 56DC55E02AAA7471003E8AFD /* Attestation.h in Sources */ = {isa = PBXBuildFile; fileRef = B3E7B5881CC2AC0600A0062D /* Attestation.h */; };
11
+ 56DC55E12AAA7471003E8AFD /* Attestation.mm in Sources */ = {isa = PBXBuildFile; fileRef = B3E7B5891CC2AC0600A0062D /* Attestation.mm */; };
12
+ /* End PBXBuildFile section */
13
+
14
+ /* Begin PBXCopyFilesBuildPhase section */
15
+ 58B511D91A9E6C8500147676 /* CopyFiles */ = {
16
+ isa = PBXCopyFilesBuildPhase;
17
+ buildActionMask = 2147483647;
18
+ dstPath = "include/$(PRODUCT_NAME)";
19
+ dstSubfolderSpec = 16;
20
+ files = (
21
+ );
22
+ runOnlyForDeploymentPostprocessing = 0;
23
+ };
24
+ /* End PBXCopyFilesBuildPhase section */
25
+
26
+ /* Begin PBXFileReference section */
27
+ 134814201AA4EA6300B7C361 /* libAttestation.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libAttestation.a; sourceTree = BUILT_PRODUCTS_DIR; };
28
+ B3E7B5881CC2AC0600A0062D /* Attestation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Attestation.h; sourceTree = "<group>"; };
29
+ B3E7B5891CC2AC0600A0062D /* Attestation.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = Attestation.mm; sourceTree = "<group>"; };
30
+ /* End PBXFileReference section */
31
+
32
+ /* Begin PBXFrameworksBuildPhase section */
33
+ 58B511D81A9E6C8500147676 /* Frameworks */ = {
34
+ isa = PBXFrameworksBuildPhase;
35
+ buildActionMask = 2147483647;
36
+ files = (
37
+ );
38
+ runOnlyForDeploymentPostprocessing = 0;
39
+ };
40
+ /* End PBXFrameworksBuildPhase section */
41
+
42
+ /* Begin PBXGroup section */
43
+ 134814211AA4EA7D00B7C361 /* Products */ = {
44
+ isa = PBXGroup;
45
+ children = (
46
+ 134814201AA4EA6300B7C361 /* libAttestation.a */,
47
+ );
48
+ name = Products;
49
+ sourceTree = "<group>";
50
+ };
51
+ 58B511D21A9E6C8500147676 = {
52
+ isa = PBXGroup;
53
+ children = (
54
+ B3E7B5881CC2AC0600A0062D /* Attestation.h */,
55
+ B3E7B5891CC2AC0600A0062D /* Attestation.mm */,
56
+ 134814211AA4EA7D00B7C361 /* Products */,
57
+ );
58
+ sourceTree = "<group>";
59
+ };
60
+ /* End PBXGroup section */
61
+
62
+ /* Begin PBXNativeTarget section */
63
+ 58B511DA1A9E6C8500147676 /* Attestation */ = {
64
+ isa = PBXNativeTarget;
65
+ buildConfigurationList = 58B511EF1A9E6C8500147676 /* Build configuration list for PBXNativeTarget "Attestation" */;
66
+ buildPhases = (
67
+ 58B511D71A9E6C8500147676 /* Sources */,
68
+ 58B511D81A9E6C8500147676 /* Frameworks */,
69
+ 58B511D91A9E6C8500147676 /* CopyFiles */,
70
+ );
71
+ buildRules = (
72
+ );
73
+ dependencies = (
74
+ );
75
+ name = Attestation;
76
+ productName = RCTDataManager;
77
+ productReference = 134814201AA4EA6300B7C361 /* libAttestation.a */;
78
+ productType = "com.apple.product-type.library.static";
79
+ };
80
+ /* End PBXNativeTarget section */
81
+
82
+ /* Begin PBXProject section */
83
+ 58B511D31A9E6C8500147676 /* Project object */ = {
84
+ isa = PBXProject;
85
+ attributes = {
86
+ LastUpgradeCheck = 0920;
87
+ ORGANIZATIONNAME = Facebook;
88
+ TargetAttributes = {
89
+ 58B511DA1A9E6C8500147676 = {
90
+ CreatedOnToolsVersion = 6.1.1;
91
+ };
92
+ };
93
+ };
94
+ buildConfigurationList = 58B511D61A9E6C8500147676 /* Build configuration list for PBXProject "Attestation" */;
95
+ compatibilityVersion = "Xcode 3.2";
96
+ developmentRegion = English;
97
+ hasScannedForEncodings = 0;
98
+ knownRegions = (
99
+ English,
100
+ en,
101
+ );
102
+ mainGroup = 58B511D21A9E6C8500147676;
103
+ productRefGroup = 58B511D21A9E6C8500147676;
104
+ projectDirPath = "";
105
+ projectRoot = "";
106
+ targets = (
107
+ 58B511DA1A9E6C8500147676 /* Attestation */,
108
+ );
109
+ };
110
+ /* End PBXProject section */
111
+
112
+ /* Begin PBXSourcesBuildPhase section */
113
+ 58B511D71A9E6C8500147676 /* Sources */ = {
114
+ isa = PBXSourcesBuildPhase;
115
+ buildActionMask = 2147483647;
116
+ files = (
117
+ 56DC55E02AAA7471003E8AFD /* Attestation.h in Sources */,
118
+ 56DC55E12AAA7471003E8AFD /* Attestation.mm in Sources */,
119
+ );
120
+ runOnlyForDeploymentPostprocessing = 0;
121
+ };
122
+ /* End PBXSourcesBuildPhase section */
123
+
124
+ /* Begin XCBuildConfiguration section */
125
+ 58B511ED1A9E6C8500147676 /* Debug */ = {
126
+ isa = XCBuildConfiguration;
127
+ buildSettings = {
128
+ ALWAYS_SEARCH_USER_PATHS = NO;
129
+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
130
+ CLANG_CXX_LIBRARY = "libc++";
131
+ CLANG_ENABLE_MODULES = YES;
132
+ CLANG_ENABLE_OBJC_ARC = YES;
133
+ CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
134
+ CLANG_WARN_BOOL_CONVERSION = YES;
135
+ CLANG_WARN_COMMA = YES;
136
+ CLANG_WARN_CONSTANT_CONVERSION = YES;
137
+ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
138
+ CLANG_WARN_EMPTY_BODY = YES;
139
+ CLANG_WARN_ENUM_CONVERSION = YES;
140
+ CLANG_WARN_INFINITE_RECURSION = YES;
141
+ CLANG_WARN_INT_CONVERSION = YES;
142
+ CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
143
+ CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
144
+ CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
145
+ CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
146
+ CLANG_WARN_STRICT_PROTOTYPES = YES;
147
+ CLANG_WARN_SUSPICIOUS_MOVE = YES;
148
+ CLANG_WARN_UNREACHABLE_CODE = YES;
149
+ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
150
+ COPY_PHASE_STRIP = NO;
151
+ ENABLE_STRICT_OBJC_MSGSEND = YES;
152
+ ENABLE_TESTABILITY = YES;
153
+ "EXCLUDED_ARCHS[sdk=*]" = arm64;
154
+ GCC_C_LANGUAGE_STANDARD = gnu99;
155
+ GCC_DYNAMIC_NO_PIC = NO;
156
+ GCC_NO_COMMON_BLOCKS = YES;
157
+ GCC_OPTIMIZATION_LEVEL = 0;
158
+ GCC_PREPROCESSOR_DEFINITIONS = (
159
+ "DEBUG=1",
160
+ "$(inherited)",
161
+ );
162
+ GCC_SYMBOLS_PRIVATE_EXTERN = NO;
163
+ GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
164
+ GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
165
+ GCC_WARN_UNDECLARED_SELECTOR = YES;
166
+ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
167
+ GCC_WARN_UNUSED_FUNCTION = YES;
168
+ GCC_WARN_UNUSED_VARIABLE = YES;
169
+ IPHONEOS_DEPLOYMENT_TARGET = 12.0;
170
+ MTL_ENABLE_DEBUG_INFO = YES;
171
+ ONLY_ACTIVE_ARCH = YES;
172
+ SDKROOT = iphoneos;
173
+ };
174
+ name = Debug;
175
+ };
176
+ 58B511EE1A9E6C8500147676 /* Release */ = {
177
+ isa = XCBuildConfiguration;
178
+ buildSettings = {
179
+ ALWAYS_SEARCH_USER_PATHS = NO;
180
+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
181
+ CLANG_CXX_LIBRARY = "libc++";
182
+ CLANG_ENABLE_MODULES = YES;
183
+ CLANG_ENABLE_OBJC_ARC = YES;
184
+ CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
185
+ CLANG_WARN_BOOL_CONVERSION = YES;
186
+ CLANG_WARN_COMMA = YES;
187
+ CLANG_WARN_CONSTANT_CONVERSION = YES;
188
+ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
189
+ CLANG_WARN_EMPTY_BODY = YES;
190
+ CLANG_WARN_ENUM_CONVERSION = YES;
191
+ CLANG_WARN_INFINITE_RECURSION = YES;
192
+ CLANG_WARN_INT_CONVERSION = YES;
193
+ CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
194
+ CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
195
+ CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
196
+ CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
197
+ CLANG_WARN_STRICT_PROTOTYPES = YES;
198
+ CLANG_WARN_SUSPICIOUS_MOVE = YES;
199
+ CLANG_WARN_UNREACHABLE_CODE = YES;
200
+ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
201
+ COPY_PHASE_STRIP = YES;
202
+ ENABLE_NS_ASSERTIONS = NO;
203
+ ENABLE_STRICT_OBJC_MSGSEND = YES;
204
+ "EXCLUDED_ARCHS[sdk=*]" = arm64;
205
+ GCC_C_LANGUAGE_STANDARD = gnu99;
206
+ GCC_NO_COMMON_BLOCKS = YES;
207
+ GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
208
+ GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
209
+ GCC_WARN_UNDECLARED_SELECTOR = YES;
210
+ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
211
+ GCC_WARN_UNUSED_FUNCTION = YES;
212
+ GCC_WARN_UNUSED_VARIABLE = YES;
213
+ IPHONEOS_DEPLOYMENT_TARGET = 12.0;
214
+ MTL_ENABLE_DEBUG_INFO = NO;
215
+ SDKROOT = iphoneos;
216
+ VALIDATE_PRODUCT = YES;
217
+ };
218
+ name = Release;
219
+ };
220
+ 58B511F01A9E6C8500147676 /* Debug */ = {
221
+ isa = XCBuildConfiguration;
222
+ buildSettings = {
223
+ HEADER_SEARCH_PATHS = (
224
+ "$(inherited)",
225
+ /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include,
226
+ "$(SRCROOT)/../../../React/**",
227
+ "$(SRCROOT)/../../react-native/React/**",
228
+ );
229
+ LIBRARY_SEARCH_PATHS = "$(inherited)";
230
+ OTHER_LDFLAGS = "-ObjC";
231
+ PRODUCT_NAME = Attestation;
232
+ SKIP_INSTALL = YES;
233
+ };
234
+ name = Debug;
235
+ };
236
+ 58B511F11A9E6C8500147676 /* Release */ = {
237
+ isa = XCBuildConfiguration;
238
+ buildSettings = {
239
+ HEADER_SEARCH_PATHS = (
240
+ "$(inherited)",
241
+ /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include,
242
+ "$(SRCROOT)/../../../React/**",
243
+ "$(SRCROOT)/../../react-native/React/**",
244
+ );
245
+ LIBRARY_SEARCH_PATHS = "$(inherited)";
246
+ OTHER_LDFLAGS = "-ObjC";
247
+ PRODUCT_NAME = Attestation;
248
+ SKIP_INSTALL = YES;
249
+ };
250
+ name = Release;
251
+ };
252
+ /* End XCBuildConfiguration section */
253
+
254
+ /* Begin XCConfigurationList section */
255
+ 58B511D61A9E6C8500147676 /* Build configuration list for PBXProject "Attestation" */ = {
256
+ isa = XCConfigurationList;
257
+ buildConfigurations = (
258
+ 58B511ED1A9E6C8500147676 /* Debug */,
259
+ 58B511EE1A9E6C8500147676 /* Release */,
260
+ );
261
+ defaultConfigurationIsVisible = 0;
262
+ defaultConfigurationName = Release;
263
+ };
264
+ 58B511EF1A9E6C8500147676 /* Build configuration list for PBXNativeTarget "Attestation" */ = {
265
+ isa = XCConfigurationList;
266
+ buildConfigurations = (
267
+ 58B511F01A9E6C8500147676 /* Debug */,
268
+ 58B511F11A9E6C8500147676 /* Release */,
269
+ );
270
+ defaultConfigurationIsVisible = 0;
271
+ defaultConfigurationName = Release;
272
+ };
273
+ /* End XCConfigurationList section */
274
+ };
275
+ rootObject = 58B511D31A9E6C8500147676 /* Project object */;
276
+ }