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