1// Copyright 2019-present 650 Industries. All rights reserved.
2
3#import <ExpoModulesCore/EXPermissionsService.h>
4
5#import "EXPermissionsManager.h"
6#import "EXEnvironment.h"
7
8NSString * const EXPermissionsKey = @"ExpoPermissions";
9
10@interface EXPermissionsManager ()
11
12@property (nonatomic, strong) NSMutableDictionary<NSString *, NSDictionary *> *permissionsCache;
13
14@end
15
16@implementation EXPermissionsManager
17
18- (instancetype)init
19{
20  if (self = [super init]) {
21    NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
22    NSDictionary *expoPermissions = [userDefaults dictionaryForKey:EXPermissionsKey];
23    _permissionsCache = expoPermissions ? [[NSMutableDictionary alloc] initWithDictionary:expoPermissions] : [NSMutableDictionary new];
24  }
25  return self;
26}
27
28EX_REGISTER_SINGLETON_MODULE(Permissions)
29
30- (EXPermissionStatus)getPermission:(NSString *)permissionType forExperience:(NSString *)scopeKey
31{
32  permissionType = [EXPermissionsManager mapPermissionType:permissionType];
33
34  NSString *scopeKeyKey = [EXPermissionsManager escapedResourceName:scopeKey];
35  NSDictionary *experiencePermissions = _permissionsCache[scopeKeyKey];
36  if (!experiencePermissions) {
37    return EXPermissionStatusUndetermined;
38  }
39
40  NSDictionary *permissionData = experiencePermissions[permissionType];
41  if (!permissionData) {
42    return EXPermissionStatusUndetermined;
43  }
44
45  if ([permissionData[@"status"] isEqualToString:[EXPermissionsService permissionStringForStatus:EXPermissionStatusGranted]]) {
46    return EXPermissionStatusGranted;
47  }
48
49  return EXPermissionStatusDenied;
50}
51
52- (BOOL)hasGrantedPermission:(NSString *)permission forExperience:(NSString *)scopeKey
53{
54  if ([EXEnvironment sharedEnvironment].isDetached) {
55    return YES;
56  }
57
58  return [self getPermission:[EXPermissionsManager mapPermissionType:permission] forExperience:scopeKey] == EXPermissionStatusGranted;
59}
60
61- (BOOL)savePermission:(NSDictionary *)permission ofType:(NSString *)type forExperience:(NSString *)scopeKey
62{
63  type = [EXPermissionsManager mapPermissionType:type];
64
65  NSString *scopeKeyKey = [EXPermissionsManager escapedResourceName:scopeKey];
66  NSMutableDictionary *experiencePermissions;
67  if ([_permissionsCache objectForKey:scopeKeyKey] == nil) {
68    experiencePermissions = [[NSMutableDictionary alloc] init];
69  } else {
70    experiencePermissions = [[NSMutableDictionary alloc] initWithDictionary:_permissionsCache[scopeKeyKey]];
71  }
72
73  experiencePermissions[type] = permission;
74  _permissionsCache[scopeKeyKey] = experiencePermissions;
75  [self synchronizeWithPermissions:_permissionsCache];
76  return YES;
77}
78
79- (void)synchronizeWithPermissions:(NSDictionary *)permissions
80{
81  [[NSUserDefaults standardUserDefaults] setObject:permissions forKey:EXPermissionsKey];
82}
83
84+ (NSString *)escapedResourceName:(NSString *)name
85{
86  NSString *charactersToEscape = @"!*'();:@&=+$,/?%#[]";
87  NSCharacterSet *allowedCharacters = [[NSCharacterSet characterSetWithCharactersInString:charactersToEscape] invertedSet];
88  return [name stringByAddingPercentEncodingWithAllowedCharacters:allowedCharacters];
89}
90
91+ (NSString *)mapPermissionType:(NSString *)type
92{
93  if ([type isEqual:@"locationForeground"]) {
94    return @"location";
95  }
96
97  return type;
98}
99
100@end
101