├── README.md ├── iOSMDMAgent ├── sound │ └── sound.caf ├── Images.xcassets │ ├── Contents.json │ ├── header.imageset │ │ ├── header.png │ │ └── Contents.json │ ├── reload.imageset │ │ ├── reload.png │ │ └── Contents.json │ ├── ButtonImages.imageset │ │ ├── btn_orange.png │ │ ├── btn_orange@2x.png │ │ ├── btn_orange@3x.png │ │ └── Contents.json │ ├── SplashMain.imageset │ │ ├── SplashMain.png │ │ └── Contents.json │ ├── i57.imageset │ │ ├── Icon-App-57x57@1x.png │ │ ├── Icon-App-57x57@2x.png │ │ └── Contents.json │ ├── i60.imageset │ │ ├── Icon-App-60x60@1x.png │ │ ├── Icon-App-60x60@2x.png │ │ ├── Icon-App-60x60@3x.png │ │ └── Contents.json │ ├── i72.imageset │ │ ├── Icon-App-72x72@1x.png │ │ ├── Icon-App-72x72@2x.png │ │ └── Contents.json │ ├── AppIcon.appiconset │ │ ├── Icon-App-20x20@1x.png │ │ ├── Icon-App-20x20@2x.png │ │ ├── Icon-App-20x20@3x.png │ │ ├── Icon-App-29x29@1x.png │ │ ├── Icon-App-29x29@2x.png │ │ ├── Icon-App-29x29@3x.png │ │ ├── Icon-App-40x40@1x.png │ │ ├── Icon-App-40x40@2x.png │ │ ├── Icon-App-40x40@3x.png │ │ ├── Icon-App-60x60@2x.png │ │ ├── Icon-App-60x60@3x.png │ │ ├── Icon-App-76x76@1x.png │ │ ├── Icon-App-76x76@2x.png │ │ ├── Icon-App-20x20@2x-1.png │ │ ├── Icon-App-29x29@2x-1.png │ │ ├── Icon-App-40x40@2x-1.png │ │ ├── Icon-App-83.5x83.5@2x.png │ │ └── Contents.json │ └── LaunchImage.launchimage │ │ ├── Default~iphone.png │ │ ├── Default-Portrait~ipad_768x1024.png │ │ ├── Default-Landscape~ipad_1024x768.png │ │ ├── Default-Landscape@2x~ipad_2048x1536.png │ │ ├── Default-Portrait@2x~ipad_1536x2048.png │ │ ├── Default-750@2x~iphone6-portrait_750x1334.png │ │ ├── Default-1242@3x~iphone6s-portrait_1242x2208.png │ │ ├── Default-750@2x~iphone6-portrait_750x1334-1.png │ │ ├── Default-1242@3x~iphone6s-portrait_1242x2208-1.png │ │ └── Contents.json ├── SDKProtocol.h ├── iOSMDMAgent.entitlements ├── main.m ├── LoginViewController.h ├── ManagedAppConfig.plist ├── MDMConstants.h ├── ConnectionUtils.h ├── ViewController.h ├── MDMConstants.m ├── AppDelegate.h ├── Endpoints.plist ├── MDMUtils.h ├── URLUtils.h ├── ViewController.m ├── Info.plist ├── LoginViewController.m ├── KeychainItemWrapper.h ├── Base.lproj │ ├── LaunchScreen.xib │ └── Main.storyboard ├── URLUtils.m ├── MDMUtils.m ├── KeychainItemWrapper.m ├── ConnectionUtils.m └── AppDelegate.m ├── .gitignore ├── iOSMDMAgentTests ├── Info.plist └── iOSMDMAgentTests.m ├── issue_template.md ├── pull_request_template.md └── iOSMDMAgent.xcodeproj └── project.pbxproj /README.md: -------------------------------------------------------------------------------- 1 | WSO2 EMM iOS Agent 2 | ================ 3 | 4 | This is the iOS agent code repository of WSO2 EMM 5 | -------------------------------------------------------------------------------- /iOSMDMAgent/sound/sound.caf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wso2/cdmf-agent-ios/HEAD/iOSMDMAgent/sound/sound.caf -------------------------------------------------------------------------------- /iOSMDMAgent/Images.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | } 6 | } -------------------------------------------------------------------------------- /iOSMDMAgent/Images.xcassets/header.imageset/header.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wso2/cdmf-agent-ios/HEAD/iOSMDMAgent/Images.xcassets/header.imageset/header.png -------------------------------------------------------------------------------- /iOSMDMAgent/Images.xcassets/reload.imageset/reload.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wso2/cdmf-agent-ios/HEAD/iOSMDMAgent/Images.xcassets/reload.imageset/reload.png -------------------------------------------------------------------------------- /iOSMDMAgent/Images.xcassets/ButtonImages.imageset/btn_orange.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wso2/cdmf-agent-ios/HEAD/iOSMDMAgent/Images.xcassets/ButtonImages.imageset/btn_orange.png -------------------------------------------------------------------------------- /iOSMDMAgent/Images.xcassets/SplashMain.imageset/SplashMain.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wso2/cdmf-agent-ios/HEAD/iOSMDMAgent/Images.xcassets/SplashMain.imageset/SplashMain.png -------------------------------------------------------------------------------- /iOSMDMAgent/Images.xcassets/i57.imageset/Icon-App-57x57@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wso2/cdmf-agent-ios/HEAD/iOSMDMAgent/Images.xcassets/i57.imageset/Icon-App-57x57@1x.png -------------------------------------------------------------------------------- /iOSMDMAgent/Images.xcassets/i57.imageset/Icon-App-57x57@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wso2/cdmf-agent-ios/HEAD/iOSMDMAgent/Images.xcassets/i57.imageset/Icon-App-57x57@2x.png -------------------------------------------------------------------------------- /iOSMDMAgent/Images.xcassets/i60.imageset/Icon-App-60x60@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wso2/cdmf-agent-ios/HEAD/iOSMDMAgent/Images.xcassets/i60.imageset/Icon-App-60x60@1x.png -------------------------------------------------------------------------------- /iOSMDMAgent/Images.xcassets/i60.imageset/Icon-App-60x60@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wso2/cdmf-agent-ios/HEAD/iOSMDMAgent/Images.xcassets/i60.imageset/Icon-App-60x60@2x.png -------------------------------------------------------------------------------- /iOSMDMAgent/Images.xcassets/i60.imageset/Icon-App-60x60@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wso2/cdmf-agent-ios/HEAD/iOSMDMAgent/Images.xcassets/i60.imageset/Icon-App-60x60@3x.png -------------------------------------------------------------------------------- /iOSMDMAgent/Images.xcassets/i72.imageset/Icon-App-72x72@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wso2/cdmf-agent-ios/HEAD/iOSMDMAgent/Images.xcassets/i72.imageset/Icon-App-72x72@1x.png -------------------------------------------------------------------------------- /iOSMDMAgent/Images.xcassets/i72.imageset/Icon-App-72x72@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wso2/cdmf-agent-ios/HEAD/iOSMDMAgent/Images.xcassets/i72.imageset/Icon-App-72x72@2x.png -------------------------------------------------------------------------------- /iOSMDMAgent/Images.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wso2/cdmf-agent-ios/HEAD/iOSMDMAgent/Images.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png -------------------------------------------------------------------------------- /iOSMDMAgent/Images.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wso2/cdmf-agent-ios/HEAD/iOSMDMAgent/Images.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png -------------------------------------------------------------------------------- /iOSMDMAgent/Images.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wso2/cdmf-agent-ios/HEAD/iOSMDMAgent/Images.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png -------------------------------------------------------------------------------- /iOSMDMAgent/Images.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wso2/cdmf-agent-ios/HEAD/iOSMDMAgent/Images.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png -------------------------------------------------------------------------------- /iOSMDMAgent/Images.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wso2/cdmf-agent-ios/HEAD/iOSMDMAgent/Images.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png -------------------------------------------------------------------------------- /iOSMDMAgent/Images.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wso2/cdmf-agent-ios/HEAD/iOSMDMAgent/Images.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png -------------------------------------------------------------------------------- /iOSMDMAgent/Images.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wso2/cdmf-agent-ios/HEAD/iOSMDMAgent/Images.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png -------------------------------------------------------------------------------- /iOSMDMAgent/Images.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wso2/cdmf-agent-ios/HEAD/iOSMDMAgent/Images.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png -------------------------------------------------------------------------------- /iOSMDMAgent/Images.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wso2/cdmf-agent-ios/HEAD/iOSMDMAgent/Images.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png -------------------------------------------------------------------------------- /iOSMDMAgent/Images.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wso2/cdmf-agent-ios/HEAD/iOSMDMAgent/Images.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png -------------------------------------------------------------------------------- /iOSMDMAgent/Images.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wso2/cdmf-agent-ios/HEAD/iOSMDMAgent/Images.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png -------------------------------------------------------------------------------- /iOSMDMAgent/Images.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wso2/cdmf-agent-ios/HEAD/iOSMDMAgent/Images.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png -------------------------------------------------------------------------------- /iOSMDMAgent/Images.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wso2/cdmf-agent-ios/HEAD/iOSMDMAgent/Images.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png -------------------------------------------------------------------------------- /iOSMDMAgent/Images.xcassets/ButtonImages.imageset/btn_orange@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wso2/cdmf-agent-ios/HEAD/iOSMDMAgent/Images.xcassets/ButtonImages.imageset/btn_orange@2x.png -------------------------------------------------------------------------------- /iOSMDMAgent/Images.xcassets/ButtonImages.imageset/btn_orange@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wso2/cdmf-agent-ios/HEAD/iOSMDMAgent/Images.xcassets/ButtonImages.imageset/btn_orange@3x.png -------------------------------------------------------------------------------- /iOSMDMAgent/Images.xcassets/AppIcon.appiconset/Icon-App-20x20@2x-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wso2/cdmf-agent-ios/HEAD/iOSMDMAgent/Images.xcassets/AppIcon.appiconset/Icon-App-20x20@2x-1.png -------------------------------------------------------------------------------- /iOSMDMAgent/Images.xcassets/AppIcon.appiconset/Icon-App-29x29@2x-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wso2/cdmf-agent-ios/HEAD/iOSMDMAgent/Images.xcassets/AppIcon.appiconset/Icon-App-29x29@2x-1.png -------------------------------------------------------------------------------- /iOSMDMAgent/Images.xcassets/AppIcon.appiconset/Icon-App-40x40@2x-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wso2/cdmf-agent-ios/HEAD/iOSMDMAgent/Images.xcassets/AppIcon.appiconset/Icon-App-40x40@2x-1.png -------------------------------------------------------------------------------- /iOSMDMAgent/Images.xcassets/LaunchImage.launchimage/Default~iphone.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wso2/cdmf-agent-ios/HEAD/iOSMDMAgent/Images.xcassets/LaunchImage.launchimage/Default~iphone.png -------------------------------------------------------------------------------- /iOSMDMAgent/Images.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wso2/cdmf-agent-ios/HEAD/iOSMDMAgent/Images.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png -------------------------------------------------------------------------------- /iOSMDMAgent/Images.xcassets/LaunchImage.launchimage/Default-Portrait~ipad_768x1024.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wso2/cdmf-agent-ios/HEAD/iOSMDMAgent/Images.xcassets/LaunchImage.launchimage/Default-Portrait~ipad_768x1024.png -------------------------------------------------------------------------------- /iOSMDMAgent/Images.xcassets/LaunchImage.launchimage/Default-Landscape~ipad_1024x768.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wso2/cdmf-agent-ios/HEAD/iOSMDMAgent/Images.xcassets/LaunchImage.launchimage/Default-Landscape~ipad_1024x768.png -------------------------------------------------------------------------------- /iOSMDMAgent/Images.xcassets/LaunchImage.launchimage/Default-Landscape@2x~ipad_2048x1536.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wso2/cdmf-agent-ios/HEAD/iOSMDMAgent/Images.xcassets/LaunchImage.launchimage/Default-Landscape@2x~ipad_2048x1536.png -------------------------------------------------------------------------------- /iOSMDMAgent/Images.xcassets/LaunchImage.launchimage/Default-Portrait@2x~ipad_1536x2048.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wso2/cdmf-agent-ios/HEAD/iOSMDMAgent/Images.xcassets/LaunchImage.launchimage/Default-Portrait@2x~ipad_1536x2048.png -------------------------------------------------------------------------------- /iOSMDMAgent/Images.xcassets/LaunchImage.launchimage/Default-750@2x~iphone6-portrait_750x1334.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wso2/cdmf-agent-ios/HEAD/iOSMDMAgent/Images.xcassets/LaunchImage.launchimage/Default-750@2x~iphone6-portrait_750x1334.png -------------------------------------------------------------------------------- /iOSMDMAgent/Images.xcassets/LaunchImage.launchimage/Default-1242@3x~iphone6s-portrait_1242x2208.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wso2/cdmf-agent-ios/HEAD/iOSMDMAgent/Images.xcassets/LaunchImage.launchimage/Default-1242@3x~iphone6s-portrait_1242x2208.png -------------------------------------------------------------------------------- /iOSMDMAgent/Images.xcassets/LaunchImage.launchimage/Default-750@2x~iphone6-portrait_750x1334-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wso2/cdmf-agent-ios/HEAD/iOSMDMAgent/Images.xcassets/LaunchImage.launchimage/Default-750@2x~iphone6-portrait_750x1334-1.png -------------------------------------------------------------------------------- /iOSMDMAgent/Images.xcassets/LaunchImage.launchimage/Default-1242@3x~iphone6s-portrait_1242x2208-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wso2/cdmf-agent-ios/HEAD/iOSMDMAgent/Images.xcassets/LaunchImage.launchimage/Default-1242@3x~iphone6s-portrait_1242x2208-1.png -------------------------------------------------------------------------------- /iOSMDMAgent/SDKProtocol.h: -------------------------------------------------------------------------------- 1 | // 2 | // SDKProtocol.h 3 | // iOSMDMAgent 4 | 5 | 6 | #import 7 | 8 | @protocol SDKProtocol 9 | 10 | @optional 11 | 12 | - (void)unregisterSuccessful; 13 | - (void)unregisterFailure:(NSError *)error; 14 | 15 | @end 16 | -------------------------------------------------------------------------------- /iOSMDMAgent/iOSMDMAgent.entitlements: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | aps-environment 6 | development 7 | 8 | 9 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ###### Xcode 2 | .DS_Store 3 | .Trashes 4 | *.swp 5 | *.lock 6 | *~.nib 7 | DerivedData/ 8 | build/ 9 | *.pbxuser 10 | *.mode1v3 11 | *.mode2v3 12 | *.perspectivev3 13 | profile 14 | 15 | *.xcworkspace 16 | !default.xcworkspace 17 | !default.pbxuser 18 | !default.mode1v3 19 | !default.mode2v3 20 | !default.perspectivev3 21 | xcuserdata 22 | *.moved-aside 23 | agent.xcodeproj/project.xcworkspace/xcuserdata/ 24 | *~ 25 | -------------------------------------------------------------------------------- /iOSMDMAgent/Images.xcassets/header.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "header.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /iOSMDMAgent/Images.xcassets/reload.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "reload.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /iOSMDMAgent/Images.xcassets/SplashMain.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "SplashMain.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /iOSMDMAgent/main.m: -------------------------------------------------------------------------------- 1 | // 2 | // main.m 3 | // iOSMDMAgent 4 | // 5 | 6 | //sound files downloaded from 7 | //https://code.google.com/p/audio-queue-caf-sample/downloads/list 8 | //MIT license 9 | //http://opensource.org/licenses/mit-license.php 10 | 11 | #import 12 | #import "AppDelegate.h" 13 | 14 | int main(int argc, char * argv[]) { 15 | @autoreleasepool { 16 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /iOSMDMAgent/Images.xcassets/i57.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "Icon-App-57x57@1x.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "filename" : "Icon-App-57x57@2x.png", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "idiom" : "universal", 15 | "scale" : "3x" 16 | } 17 | ], 18 | "info" : { 19 | "version" : 1, 20 | "author" : "xcode" 21 | } 22 | } -------------------------------------------------------------------------------- /iOSMDMAgent/Images.xcassets/i72.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "Icon-App-72x72@1x.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "filename" : "Icon-App-72x72@2x.png", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "idiom" : "universal", 15 | "scale" : "3x" 16 | } 17 | ], 18 | "info" : { 19 | "version" : 1, 20 | "author" : "xcode" 21 | } 22 | } -------------------------------------------------------------------------------- /iOSMDMAgent/Images.xcassets/ButtonImages.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x", 6 | "filename" : "btn_orange.png" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x", 11 | "filename" : "btn_orange@2x.png" 12 | }, 13 | { 14 | "idiom" : "universal", 15 | "scale" : "3x", 16 | "filename" : "btn_orange@3x.png" 17 | } 18 | ], 19 | "info" : { 20 | "version" : 1, 21 | "author" : "xcode" 22 | } 23 | } -------------------------------------------------------------------------------- /iOSMDMAgent/Images.xcassets/i60.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "Icon-App-60x60@1x.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "filename" : "Icon-App-60x60@2x.png", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "idiom" : "universal", 15 | "filename" : "Icon-App-60x60@3x.png", 16 | "scale" : "3x" 17 | } 18 | ], 19 | "info" : { 20 | "version" : 1, 21 | "author" : "xcode" 22 | } 23 | } -------------------------------------------------------------------------------- /iOSMDMAgent/LoginViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // LoginViewController.h 3 | // iOSMDMAgent 4 | // 5 | // Created by Dilshan Edirisuriya on 2/5/15. 6 | // Copyright (c) 2015 WSO2. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "MDMUtils.h" 11 | #import "MDMConstants.h" 12 | 13 | @interface LoginViewController : UIViewController 14 | 15 | @property (weak, nonatomic) IBOutlet UIButton *btnRegister; 16 | @property (strong, nonatomic) IBOutlet UITextField *txtServer; 17 | 18 | - (IBAction)clickOnRegister:(id)sender; 19 | - (void)enroll; 20 | 21 | @end 22 | -------------------------------------------------------------------------------- /iOSMDMAgent/ManagedAppConfig.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | enrollmentURL 6 | 7 | serverURL 8 | 9 | UDID 10 | 11 | clientSecret 12 | 13 | clientId 14 | 15 | accessToken 16 | 17 | refreshToken 18 | 19 | depEnabled 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /iOSMDMAgent/MDMConstants.h: -------------------------------------------------------------------------------- 1 | // 2 | // MDMConstants.h 3 | // iOSMDMAgent 4 | // 5 | // 6 | 7 | #import 8 | 9 | @interface MDMConstants : NSObject 10 | 11 | extern NSString *const OK_BUTTON_TEXT; 12 | extern NSString *const CANCEL_BUTTON_TEXT; 13 | extern NSString *const EMPTY_URL; 14 | extern NSString *const EMPTY_URL_MESSAGE; 15 | extern NSString *const AUTH_ERROR_TITLE; 16 | extern NSString *const AUTH_ERROR_MESSAGE; 17 | extern NSString *const INVALID_SERVER_URL; 18 | extern NSString *const INVALID_SERVER_URL_MESSAGE; 19 | extern NSString *const UNREGISTER_ERROR; 20 | extern NSString *const UNREGISTER_ERROR_MESSAGE; 21 | 22 | @end 23 | -------------------------------------------------------------------------------- /iOSMDMAgent/ConnectionUtils.h: -------------------------------------------------------------------------------- 1 | // 2 | // ConnectionUtils.h 3 | // iOSMDMAgent 4 | 5 | 6 | #import 7 | #import "SDKProtocol.h" 8 | 9 | @interface ConnectionUtils : NSObject 10 | 11 | @property(nonatomic, assign) id delegate; 12 | 13 | - (void)sendPushTokenToServer:(NSString *)udid pushToken:(NSString *)token; 14 | - (void)sendLocationToServer:(NSString *)udid latitiude:(float)lat longitude:(float)longi; 15 | - (void)sendUnenrollToServer; 16 | - (void)sendOperationUpdateToServer:(NSString *)deviceId operationId:(NSString *)opId status:(NSString *)state; 17 | - (void)enforceEffectivePolicy:(NSString *)deviceId; 18 | 19 | @end 20 | -------------------------------------------------------------------------------- /iOSMDMAgent/ViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.h 3 | // iOSMDMAgent 4 | // 5 | // Created by Dilshan Edirisuriya on 2/5/15. 6 | // Copyright (c) 2015 WSO2. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "SDKProtocol.h" 11 | #import "MDMConstants.h" 12 | 13 | @interface ViewController : UIViewController 14 | 15 | @property (weak, nonatomic) IBOutlet UIButton *btnUnRegister; 16 | @property (strong, nonatomic) IBOutlet UIButton *btnRefresh; 17 | 18 | 19 | @property (strong, nonatomic) IBOutlet UILabel *lbLocationSync; 20 | 21 | 22 | - (IBAction)clickOnUnRegister:(id)sender; 23 | - (IBAction)refresh:(id)sender; 24 | 25 | @end 26 | 27 | -------------------------------------------------------------------------------- /iOSMDMAgentTests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | 24 | 25 | -------------------------------------------------------------------------------- /iOSMDMAgent/MDMConstants.m: -------------------------------------------------------------------------------- 1 | // 2 | // MDMConstants.m 3 | // iOSMDMAgent 4 | // 5 | 6 | 7 | #import "MDMConstants.h" 8 | 9 | @implementation MDMConstants 10 | 11 | NSString *const OK_BUTTON_TEXT = @"OK"; 12 | NSString *const CANCEL_BUTTON_TEXT = @"Cancel"; 13 | NSString *const EMPTY_URL = @"Error"; 14 | NSString *const EMPTY_URL_MESSAGE = @"Server url is empty. Please type a valid server url."; 15 | NSString *const AUTH_ERROR_TITLE = @"Authentication Error"; 16 | NSString *const AUTH_ERROR_MESSAGE = @"Authentication Error. Please check your credentials."; 17 | NSString *const INVALID_SERVER_URL = @"Invalid Server URL"; 18 | NSString *const INVALID_SERVER_URL_MESSAGE = @"Invalid server url. Please check your server url."; 19 | NSString *const UNREGISTER_ERROR = @"Error"; 20 | NSString *const UNREGISTER_ERROR_MESSAGE = @"Error occurred while unregistering. Please try again."; 21 | 22 | @end 23 | -------------------------------------------------------------------------------- /issue_template.md: -------------------------------------------------------------------------------- 1 | **Description:** 2 | 3 | 4 | **Suggested Labels:** 5 | 6 | 7 | **Suggested Assignees:** 8 | 9 | 10 | **Affected Product Version:** 11 | 12 | **OS, DB, other environment details and versions:** 13 | 14 | **Steps to reproduce:** 15 | 16 | 17 | **Related Issues:** 18 | -------------------------------------------------------------------------------- /iOSMDMAgent/AppDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.h 3 | // iOSMDMAgent 4 | // 5 | 6 | #import 7 | #import 8 | #import 9 | #import 10 | #import "LoginViewController.h" 11 | #import "ConnectionUtils.h" 12 | #import "SDKProtocol.h" 13 | 14 | @interface AppDelegate : UIResponder 15 | 16 | @property (strong, nonatomic) UIWindow *window; 17 | @property (strong, nonatomic) LoginViewController *loginViewController; 18 | @property (retain, nonatomic) ConnectionUtils *connectionUtils; 19 | @property (strong, nonatomic) CLLocationManager *locationManager; 20 | @property (strong, nonatomic) AVAudioPlayer *theAudio; 21 | 22 | extern NSInteger const LOCATION_OFF_CODE; 23 | 24 | - (void)showLoginViewController; 25 | - (void)authorizeLocationService; 26 | 27 | @end 28 | 29 | -------------------------------------------------------------------------------- /iOSMDMAgentTests/iOSMDMAgentTests.m: -------------------------------------------------------------------------------- 1 | // 2 | // iOSMDMAgentTests.m 3 | // iOSMDMAgentTests 4 | // 5 | // Created by Dilshan Edirisuriya on 2/5/15. 6 | // Copyright (c) 2015 WSO2. All rights reserved. 7 | // 8 | 9 | #import 10 | #import 11 | 12 | @interface iOSMDMAgentTests : XCTestCase 13 | 14 | @end 15 | 16 | @implementation iOSMDMAgentTests 17 | 18 | - (void)setUp { 19 | [super setUp]; 20 | // Put setup code here. This method is called before the invocation of each test method in the class. 21 | } 22 | 23 | - (void)tearDown { 24 | // Put teardown code here. This method is called after the invocation of each test method in the class. 25 | [super tearDown]; 26 | } 27 | 28 | - (void)testExample { 29 | // This is an example of a functional test case. 30 | XCTAssert(YES, @"Pass"); 31 | } 32 | 33 | - (void)testPerformanceExample { 34 | // This is an example of a performance test case. 35 | [self measureBlock:^{ 36 | // Put the code you want to measure the time of here. 37 | }]; 38 | } 39 | 40 | @end 41 | -------------------------------------------------------------------------------- /iOSMDMAgent/Endpoints.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | OPERATION_URI 6 | /operation/%@ 7 | REFRESH_TOKEN_URI 8 | /token 9 | UNENROLLMENT_PATH 10 | /admin/devices/enterprise-wipe 11 | SERVER_CONTEXT 12 | /api/device-mgt/ios/v1.0 13 | TOKEN_PUBLISH_URI 14 | /devices/pushtoken/%@ 15 | LOCATION_PUBLISH_URI 16 | /devices/location/%@ 17 | ENROLLMENT_URI 18 | /ios-web-agent/enrollments/ios/login-agent?isAgentAvailable=true 19 | API_PORT 20 | 8243 21 | ENROLMENT_PORT 22 | 9443 23 | ENROLLMENT_URL 24 | 25 | SERVER_URL 26 | https://gateway.api.cloudstaging.wso2.com 27 | EFFECTIVE_POLICY_PATH 28 | /devices/effective-policy/%@ 29 | TOKEN_REFRESH_URI 30 | /ios-web-agent/enrollments/ios/login-agent?isRefresh=true 31 | 32 | 33 | -------------------------------------------------------------------------------- /iOSMDMAgent/MDMUtils.h: -------------------------------------------------------------------------------- 1 | // 2 | // MDMUtils.h 3 | // iOSMDMAgent 4 | // 5 | 6 | #import 7 | 8 | @interface MDMUtils : NSObject 9 | 10 | extern int LOCATION_DISTANCE_FILTER; 11 | extern NSString *const UDID; 12 | extern NSString *const APS; 13 | extern NSString *const EXTRA; 14 | extern NSString *const OPERATION; 15 | extern NSString *const SOUND_FILE_NAME; 16 | extern NSString *const SOUND_FILE_EXTENSION; 17 | extern NSString *const ENCLOSING_TAGS; 18 | extern NSString *const TOKEN_KEYCHAIN; 19 | extern NSString *const CLIENT_DETAILS_KEYCHAIN; 20 | extern NSString *const ENROLL_STATUS; 21 | extern NSString *const ENROLLED; 22 | extern NSString *const UNENROLLED; 23 | extern NSString *const OPERATION_ID; 24 | extern NSString *const LOCATION_OPERATION_ID; 25 | extern NSString *const ACCESS_TOKEN; 26 | extern NSString *const REFRESH_TOKEN; 27 | extern NSString *const CLIENT_CREDENTIALS; 28 | 29 | extern NSString *const TENANT_DOMAIN; 30 | extern NSString *const LOCATION_UPDATED_TIME; 31 | 32 | 33 | + (void)saveDeviceUDID:(NSString *)udid; 34 | + (NSString *)getDeviceUDID; 35 | + (NSString *) getEnrollStatus; 36 | + (void) setEnrollStatus: (NSString *)value; 37 | + (NSString *) getLocationOperationId; 38 | + (void) setLocationOperationId: (NSString *)value; 39 | + (void)savePreferance:(NSString *)key value:(NSString *)val; 40 | + (NSString *)getPreferance:(NSString *)key; 41 | + (void)setAccessToken:(NSString *)accessToken; 42 | + (void)setRefreshToken:(NSString *)refreshToken; 43 | + (NSString *)getAccessToken; 44 | + (NSString *)getRefreshToken; 45 | + (void)setClientCredentials:(NSString *)clientCredentials; 46 | + (NSString *)getClientCredentials; 47 | + (void)setTenantDomain:(NSString *)tenantDomain; 48 | + (NSString *)getTenantDomain; 49 | + (void)setLocationUpdatedTime; 50 | + (NSString *)getLocationUpdatedTime; 51 | 52 | @end 53 | -------------------------------------------------------------------------------- /iOSMDMAgent/URLUtils.h: -------------------------------------------------------------------------------- 1 | // 2 | // URLUtils.h 3 | // iOSMDMAgent 4 | // 5 | 6 | 7 | #import 8 | 9 | @interface URLUtils : NSObject 10 | 11 | extern float const HTTP_REQUEST_TIME; 12 | extern int HTTP_OK; 13 | extern int HTTP_CREATED; 14 | extern int HTTP_BAD_REQUEST; 15 | extern NSString *const ENDPOINT_FILE_NAME; 16 | extern NSString *const EXTENSION; 17 | extern NSString *const TOKEN_PUBLISH_URI; 18 | extern NSString *const ENROLLMENT_URI; 19 | extern NSString *const SERVER_URL; 20 | extern NSString *const CONTEXT_URI; 21 | extern NSString *const TOKEN; 22 | extern NSString *const GET; 23 | extern NSString *const POST; 24 | extern NSString *const PUT; 25 | extern NSString *const ACCEPT; 26 | extern NSString *const CONTENT_TYPE; 27 | extern NSString *const APPLICATION_JSON; 28 | extern NSString *const LATITIUDE; 29 | extern NSString *const LONGITUDE; 30 | extern NSString *const UNENROLLMENT_PATH; 31 | extern NSString *const AUTHORIZATION_BEARER; 32 | extern NSString *const AUTHORIZATION_BASIC; 33 | extern NSString *const AUTHORIZATION; 34 | extern NSString *const REFRESH_TOKEN_URI; 35 | extern NSString *const REFRESH_TOKEN_LABEL; 36 | extern NSString *const GRANT_TYPE; 37 | extern NSString *const GRANT_TYPE_VALUE; 38 | extern NSString *const FORM_ENCODED; 39 | extern NSString *const OPERATION_URI; 40 | extern NSString *const OPERATION_ID_RESPOSNE; 41 | extern NSString *const STATUS; 42 | extern int OAUTH_FAIL_CODE; 43 | extern NSString *const ENROLLMENT_URL; 44 | extern NSString *const EFFECTIVE_POLICY_PATH; 45 | 46 | + (void)saveServerURL:(NSString *)serverURL; 47 | + (NSString *)getServerURL; 48 | + (NSString *)getEnrollmentURL; 49 | + (NSString *)getContextURL; 50 | + (NSDictionary *)readEndpoints; 51 | + (NSString *)getTokenPublishURL; 52 | + (NSString *)getLocationPublishURL; 53 | + (NSString *)getUnenrollURL; 54 | + (NSString *)getRefreshTokenURL; 55 | + (NSString *)getOperationURL; 56 | + (void)saveEnrollmentURL:(NSString *)enrollURL; 57 | + (NSString *)getSavedEnrollmentURL; 58 | + (NSString *)getEnrollmentURLFromPlist; 59 | + (NSString *)getServerURLFromPlist; 60 | + (NSString *)getEffectivePolicyURL; 61 | + (NSString *)getTokenRefreshURL; 62 | 63 | @end 64 | -------------------------------------------------------------------------------- /iOSMDMAgent/ViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.m 3 | // iOSMDMAgent 4 | // 5 | // Created by Dilshan Edirisuriya on 2/5/15. 6 | // Copyright (c) 2015 WSO2. All rights reserved. 7 | // 8 | 9 | #import "ViewController.h" 10 | #import "URLUtils.h" 11 | #import "ConnectionUtils.h" 12 | #import "MDMUtils.h" 13 | 14 | @interface ViewController () 15 | 16 | @end 17 | 18 | @implementation ViewController 19 | 20 | - (void)viewDidLoad { 21 | [super viewDidLoad]; 22 | self.lbLocationSync.text = [MDMUtils getLocationUpdatedTime]; 23 | // Do any additional setup after loading the view, typically from a nib. 24 | } 25 | 26 | - (void)didReceiveMemoryWarning { 27 | [super didReceiveMemoryWarning]; 28 | // Dispose of any resources that can be recreated. 29 | } 30 | - (IBAction)clickOnUnRegister:(id)sender { 31 | 32 | UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@"Confirm Unregister" message:@"Are you sure you want to unregister this device?" delegate:self cancelButtonTitle:@"Cancel" otherButtonTitles:@"OK", nil]; 33 | [alertView show]; 34 | } 35 | 36 | - (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex 37 | { 38 | if(buttonIndex == 1) { 39 | ConnectionUtils *connectionUtils = [[ConnectionUtils alloc] init]; 40 | connectionUtils.delegate = self; 41 | [connectionUtils sendUnenrollToServer]; 42 | } 43 | } 44 | 45 | - (void)unregisterSuccessful { 46 | dispatch_async(dispatch_get_main_queue(), ^{ 47 | [MDMUtils setEnrollStatus:UNENROLLED]; 48 | 49 | UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@"Main" bundle:nil]; 50 | UIViewController *loginViewController = [storyboard instantiateViewControllerWithIdentifier:@"loginViewController"]; 51 | [self presentViewController:loginViewController animated:TRUE completion:nil]; 52 | }); 53 | } 54 | 55 | - (void)unregisterFailure:(NSError *)error { 56 | dispatch_async(dispatch_get_main_queue(), ^{ 57 | UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:UNREGISTER_ERROR message:UNREGISTER_ERROR_MESSAGE delegate:nil cancelButtonTitle:OK_BUTTON_TEXT otherButtonTitles:nil, nil]; 58 | [alertView show]; 59 | }); 60 | } 61 | - (IBAction)refresh:(id)sender { 62 | self.lbLocationSync.text = [MDMUtils getLocationUpdatedTime]; 63 | } 64 | 65 | @end 66 | -------------------------------------------------------------------------------- /iOSMDMAgent/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | WSO2 Agent 15 | CFBundlePackageType 16 | APPL 17 | CFBundleShortVersionString 18 | 2.2.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleURLTypes 22 | 23 | 24 | CFBundleURLName 25 | wso2.carbon.emm.ios.agent 26 | CFBundleURLSchemes 27 | 28 | wso2agent 29 | 30 | 31 | 32 | CFBundleVersion 33 | Alpha 34 | LSRequiresIPhoneOS 35 | 36 | NSAppTransportSecurity 37 | 38 | NSAllowsArbitraryLoads 39 | 40 | 41 | NSLocationAlwaysAndWhenInUseUsageDescription 42 | This allows WSO2 IoT Server to retrieve your device's updated location details 43 | NSLocationAlwaysUsageDescription 44 | This allows WSO2 IoT Server to retrieve your device's updated location details 45 | NSLocationWhenInUseUsageDescription 46 | This allows WSO2 IoT Server to retrieve your device's updated location details 47 | UIBackgroundModes 48 | 49 | audio 50 | fetch 51 | location 52 | remote-notification 53 | 54 | UILaunchStoryboardName 55 | LaunchScreen 56 | UIMainStoryboardFile 57 | Main 58 | UIRequiredDeviceCapabilities 59 | 60 | armv7 61 | location-services 62 | gps 63 | 64 | UISupportedInterfaceOrientations 65 | 66 | UIInterfaceOrientationPortrait 67 | 68 | UISupportedInterfaceOrientations~ipad 69 | 70 | UIInterfaceOrientationPortrait 71 | 72 | 73 | 74 | -------------------------------------------------------------------------------- /pull_request_template.md: -------------------------------------------------------------------------------- 1 | ## Purpose 2 | > Describe the problems, issues, or needs driving this feature/fix and include links to related issues in the following format: Resolves issue1, issue2, etc. 3 | 4 | ## Goals 5 | > Describe the solutions that this feature/fix will introduce to resolve the problems described above 6 | 7 | ## Approach 8 | > Describe how you are implementing the solutions. Include an animated GIF or screenshot if the change affects the UI (email documentation@wso2.com to review all UI text). Include a link to a Markdown file or Google doc if the feature write-up is too long to paste here. 9 | 10 | ## User stories 11 | > Summary of user stories addressed by this change> 12 | 13 | ## Release note 14 | > Brief description of the new feature or bug fix as it will appear in the release notes 15 | 16 | ## Documentation 17 | > Link(s) to product documentation that addresses the changes of this PR. If no doc impact, enter “N/A” plus brief explanation of why there’s no doc impact 18 | 19 | ## Training 20 | > Link to the PR for changes to the training content in https://github.com/wso2/WSO2-Training, if applicable 21 | 22 | ## Certification 23 | > Type “Sent” when you have provided new/updated certification questions, plus four answers for each question (correct answer highlighted in bold), based on this change. Certification questions/answers should be sent to certification@wso2.com and NOT pasted in this PR. If there is no impact on certification exams, type “N/A” and explain why. 24 | 25 | ## Marketing 26 | > Link to drafts of marketing content that will describe and promote this feature, including product page changes, technical articles, blog posts, videos, etc., if applicable 27 | 28 | ## Automation tests 29 | - Unit tests 30 | > Code coverage information 31 | - Integration tests 32 | > Details about the test cases and coverage 33 | 34 | ## Security checks 35 | - Followed secure coding standards in http://wso2.com/technical-reports/wso2-secure-engineering-guidelines? yes/no 36 | - Ran FindSecurityBugs plugin and verified report? yes/no 37 | - Confirmed that this PR doesn't commit any keys, passwords, tokens, usernames, or other secrets? yes/no 38 | 39 | ## Samples 40 | > Provide high-level details about the samples related to this feature 41 | 42 | ## Related PRs 43 | > List any other related PRs 44 | 45 | ## Migrations (if applicable) 46 | > Describe migration steps and platforms on which migration has been tested 47 | 48 | ## Test environment 49 | > List all JDK versions, operating systems, databases, and browser/versions on which this feature/fix was tested 50 | 51 | ## Learning 52 | > Describe the research phase and any blog posts, patterns, libraries, or add-ons you used to solve the problem. -------------------------------------------------------------------------------- /iOSMDMAgent/Images.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "size" : "20x20", 5 | "idiom" : "iphone", 6 | "filename" : "Icon-App-20x20@2x-1.png", 7 | "scale" : "2x" 8 | }, 9 | { 10 | "size" : "20x20", 11 | "idiom" : "iphone", 12 | "filename" : "Icon-App-20x20@3x.png", 13 | "scale" : "3x" 14 | }, 15 | { 16 | "size" : "29x29", 17 | "idiom" : "iphone", 18 | "filename" : "Icon-App-29x29@2x.png", 19 | "scale" : "2x" 20 | }, 21 | { 22 | "size" : "29x29", 23 | "idiom" : "iphone", 24 | "filename" : "Icon-App-29x29@3x.png", 25 | "scale" : "3x" 26 | }, 27 | { 28 | "size" : "40x40", 29 | "idiom" : "iphone", 30 | "filename" : "Icon-App-40x40@2x.png", 31 | "scale" : "2x" 32 | }, 33 | { 34 | "size" : "40x40", 35 | "idiom" : "iphone", 36 | "filename" : "Icon-App-40x40@3x.png", 37 | "scale" : "3x" 38 | }, 39 | { 40 | "size" : "60x60", 41 | "idiom" : "iphone", 42 | "filename" : "Icon-App-60x60@2x.png", 43 | "scale" : "2x" 44 | }, 45 | { 46 | "size" : "60x60", 47 | "idiom" : "iphone", 48 | "filename" : "Icon-App-60x60@3x.png", 49 | "scale" : "3x" 50 | }, 51 | { 52 | "size" : "20x20", 53 | "idiom" : "ipad", 54 | "filename" : "Icon-App-20x20@1x.png", 55 | "scale" : "1x" 56 | }, 57 | { 58 | "size" : "20x20", 59 | "idiom" : "ipad", 60 | "filename" : "Icon-App-20x20@2x.png", 61 | "scale" : "2x" 62 | }, 63 | { 64 | "size" : "29x29", 65 | "idiom" : "ipad", 66 | "filename" : "Icon-App-29x29@1x.png", 67 | "scale" : "1x" 68 | }, 69 | { 70 | "size" : "29x29", 71 | "idiom" : "ipad", 72 | "filename" : "Icon-App-29x29@2x-1.png", 73 | "scale" : "2x" 74 | }, 75 | { 76 | "size" : "40x40", 77 | "idiom" : "ipad", 78 | "filename" : "Icon-App-40x40@1x.png", 79 | "scale" : "1x" 80 | }, 81 | { 82 | "size" : "40x40", 83 | "idiom" : "ipad", 84 | "filename" : "Icon-App-40x40@2x-1.png", 85 | "scale" : "2x" 86 | }, 87 | { 88 | "size" : "76x76", 89 | "idiom" : "ipad", 90 | "filename" : "Icon-App-76x76@1x.png", 91 | "scale" : "1x" 92 | }, 93 | { 94 | "size" : "76x76", 95 | "idiom" : "ipad", 96 | "filename" : "Icon-App-76x76@2x.png", 97 | "scale" : "2x" 98 | }, 99 | { 100 | "size" : "83.5x83.5", 101 | "idiom" : "ipad", 102 | "filename" : "Icon-App-83.5x83.5@2x.png", 103 | "scale" : "2x" 104 | }, 105 | { 106 | "idiom" : "ios-marketing", 107 | "size" : "1024x1024", 108 | "scale" : "1x" 109 | } 110 | ], 111 | "info" : { 112 | "version" : 1, 113 | "author" : "xcode" 114 | } 115 | } -------------------------------------------------------------------------------- /iOSMDMAgent/LoginViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // LoginViewController.m 3 | // iOSMDMAgent 4 | // 5 | // Created by Dilshan Edirisuriya on 2/5/15. 6 | // Copyright (c) 2015 WSO2. All rights reserved. 7 | // 8 | 9 | #import "LoginViewController.h" 10 | #import "URLUtils.h" 11 | 12 | @interface LoginViewController () 13 | 14 | @end 15 | 16 | @implementation LoginViewController 17 | - (void)viewDidLoad { 18 | [super viewDidLoad]; 19 | self.txtServer.delegate = self; 20 | // Do any additional setup after loading the view. 21 | NSString *enrollURL = [URLUtils getEnrollmentURLFromPlist]; 22 | NSString *serverURL = [URLUtils getServerURLFromPlist]; 23 | if(enrollURL && ![@"" isEqualToString:enrollURL] && serverURL && ![@"" isEqualToString:serverURL]) { 24 | [self.txtServer setText:serverURL]; 25 | } 26 | } 27 | 28 | - (void)didReceiveMemoryWarning { 29 | [super didReceiveMemoryWarning]; 30 | // Dispose of any resources that can be recreated. 31 | } 32 | 33 | /* 34 | #pragma mark - Navigation 35 | 36 | // In a storyboard-based application, you will often want to do a little preparation before navigation 37 | - (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender { 38 | // Get the new view controller using [segue destinationViewController]. 39 | // Pass the selected object to the new view controller. 40 | } 41 | */ 42 | 43 | - (IBAction)clickOnRegister:(id)sender { 44 | [self enroll]; 45 | } 46 | 47 | 48 | - (BOOL)textFieldShouldReturn:(UITextField *)textField { 49 | if (textField == self.txtServer) { 50 | [textField resignFirstResponder]; 51 | NSLog(@"Pressed GO"); 52 | [self enroll]; 53 | return NO; 54 | } 55 | NSLog(@"YES"); 56 | return YES; 57 | } 58 | 59 | - (void)enroll { 60 | NSURL *serverURL = [NSURL URLWithString:self.txtServer.text]; 61 | 62 | if (!self.txtServer || [@"" isEqualToString:self.txtServer.text]) { 63 | UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:EMPTY_URL message:EMPTY_URL_MESSAGE delegate:nil cancelButtonTitle:OK_BUTTON_TEXT otherButtonTitles:nil, nil]; 64 | [alertView show]; 65 | } else if(!serverURL) { 66 | UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:INVALID_SERVER_URL message:INVALID_SERVER_URL_MESSAGE delegate:nil cancelButtonTitle:OK_BUTTON_TEXT otherButtonTitles:nil, nil]; 67 | [alertView show]; 68 | } else { 69 | /* 70 | If the user is allowed to type the server url, assuption is this is not a production environment, 71 | Therefore, both Enrollment URL(manager node URL where the enrollment app is stored) and the gateway url are 72 | taken as the same. Check didChangeAuthorizationStatus method in AppDeligate.m for production behaviour, 73 | Where the URLs are hard coded. 74 | */ 75 | NSString *enrollURL = [URLUtils getEnrollmentURLFromPlist]; 76 | NSString *serverURL = [URLUtils getServerURLFromPlist]; 77 | if(enrollURL && ![@"" isEqualToString:enrollURL] && serverURL && ![@"" isEqualToString:serverURL]) { 78 | [URLUtils saveServerURL:serverURL]; 79 | [URLUtils saveEnrollmentURL:enrollURL]; 80 | } else { 81 | [URLUtils saveServerURL:self.txtServer.text]; 82 | [URLUtils saveEnrollmentURL:self.txtServer.text]; 83 | } 84 | [[UIApplication sharedApplication] openURL:[NSURL URLWithString:[URLUtils getEnrollmentURL]]]; 85 | } 86 | } 87 | 88 | @end 89 | -------------------------------------------------------------------------------- /iOSMDMAgent/KeychainItemWrapper.h: -------------------------------------------------------------------------------- 1 | /* 2 | File: KeychainItemWrapper.h 3 | Abstract: 4 | Objective-C wrapper for accessing a single keychain item. 5 | 6 | Version: 1.2 7 | 8 | Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple 9 | Inc. ("Apple") in consideration of your agreement to the following 10 | terms, and your use, installation, modification or redistribution of 11 | this Apple software constitutes acceptance of these terms. If you do 12 | not agree with these terms, please do not use, install, modify or 13 | redistribute this Apple software. 14 | 15 | In consideration of your agreement to abide by the following terms, and 16 | subject to these terms, Apple grants you a personal, non-exclusive 17 | license, under Apple's copyrights in this original Apple software (the 18 | "Apple Software"), to use, reproduce, modify and redistribute the Apple 19 | Software, with or without modifications, in source and/or binary forms; 20 | provided that if you redistribute the Apple Software in its entirety and 21 | without modifications, you must retain this notice and the following 22 | text and disclaimers in all such redistributions of the Apple Software. 23 | Neither the name, trademarks, service marks or logos of Apple Inc. may 24 | be used to endorse or promote products derived from the Apple Software 25 | without specific prior written permission from Apple. Except as 26 | expressly stated in this notice, no other rights or licenses, express or 27 | implied, are granted by Apple herein, including but not limited to any 28 | patent rights that may be infringed by your derivative works or by other 29 | works in which the Apple Software may be incorporated. 30 | 31 | The Apple Software is provided by Apple on an "AS IS" basis. APPLE 32 | MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION 33 | THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS 34 | FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND 35 | OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS. 36 | 37 | IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL 38 | OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 39 | SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 40 | INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, 41 | MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED 42 | AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE), 43 | STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE 44 | POSSIBILITY OF SUCH DAMAGE. 45 | 46 | Copyright (C) 2010 Apple Inc. All Rights Reserved. 47 | 48 | */ 49 | 50 | #import 51 | 52 | /* 53 | The KeychainItemWrapper class is an abstraction layer for the iPhone Keychain communication. It is merely a 54 | simple wrapper to provide a distinct barrier between all the idiosyncracies involved with the Keychain 55 | CF/NS container objects. 56 | */ 57 | @interface KeychainItemWrapper : NSObject 58 | { 59 | NSMutableDictionary *keychainItemData; // The actual keychain item data backing store. 60 | NSMutableDictionary *genericPasswordQuery; // A placeholder for the generic keychain item query used to locate the item. 61 | } 62 | 63 | @property (nonatomic, retain) NSMutableDictionary *keychainItemData; 64 | @property (nonatomic, retain) NSMutableDictionary *genericPasswordQuery; 65 | 66 | // Designated initializer. 67 | - (id)initWithIdentifier: (NSString *)identifier accessGroup:(NSString *) accessGroup; 68 | - (void)setObject:(id)inObject forKey:(id)key; 69 | - (id)objectForKey:(id)key; 70 | 71 | // Initializes and resets the default generic keychain item data. 72 | - (void)resetKeychainItem; 73 | 74 | @end -------------------------------------------------------------------------------- /iOSMDMAgent/Base.lproj/LaunchScreen.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | -------------------------------------------------------------------------------- /iOSMDMAgent/Images.xcassets/LaunchImage.launchimage/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "orientation" : "portrait", 5 | "idiom" : "iphone", 6 | "filename" : "Default~iphone.png", 7 | "extent" : "full-screen", 8 | "scale" : "1x" 9 | }, 10 | { 11 | "orientation" : "portrait", 12 | "idiom" : "iphone", 13 | "filename" : "Default-750@2x~iphone6-portrait_750x1334.png", 14 | "extent" : "full-screen", 15 | "scale" : "2x" 16 | }, 17 | { 18 | "orientation" : "portrait", 19 | "idiom" : "iphone", 20 | "filename" : "Default-1242@3x~iphone6s-portrait_1242x2208.png", 21 | "extent" : "full-screen", 22 | "subtype" : "retina4", 23 | "scale" : "2x" 24 | }, 25 | { 26 | "orientation" : "portrait", 27 | "idiom" : "ipad", 28 | "extent" : "to-status-bar", 29 | "scale" : "1x" 30 | }, 31 | { 32 | "orientation" : "portrait", 33 | "idiom" : "ipad", 34 | "extent" : "full-screen", 35 | "scale" : "1x" 36 | }, 37 | { 38 | "orientation" : "landscape", 39 | "idiom" : "ipad", 40 | "extent" : "to-status-bar", 41 | "scale" : "1x" 42 | }, 43 | { 44 | "orientation" : "landscape", 45 | "idiom" : "ipad", 46 | "extent" : "full-screen", 47 | "scale" : "1x" 48 | }, 49 | { 50 | "orientation" : "portrait", 51 | "idiom" : "ipad", 52 | "extent" : "to-status-bar", 53 | "scale" : "2x" 54 | }, 55 | { 56 | "orientation" : "portrait", 57 | "idiom" : "ipad", 58 | "extent" : "full-screen", 59 | "scale" : "2x" 60 | }, 61 | { 62 | "orientation" : "landscape", 63 | "idiom" : "ipad", 64 | "extent" : "to-status-bar", 65 | "scale" : "2x" 66 | }, 67 | { 68 | "orientation" : "landscape", 69 | "idiom" : "ipad", 70 | "extent" : "full-screen", 71 | "scale" : "2x" 72 | }, 73 | { 74 | "orientation" : "portrait", 75 | "idiom" : "iphone", 76 | "extent" : "full-screen", 77 | "minimum-system-version" : "8.0", 78 | "subtype" : "736h", 79 | "scale" : "3x" 80 | }, 81 | { 82 | "orientation" : "landscape", 83 | "idiom" : "iphone", 84 | "extent" : "full-screen", 85 | "minimum-system-version" : "8.0", 86 | "subtype" : "736h", 87 | "scale" : "3x" 88 | }, 89 | { 90 | "orientation" : "portrait", 91 | "idiom" : "iphone", 92 | "extent" : "full-screen", 93 | "minimum-system-version" : "8.0", 94 | "subtype" : "667h", 95 | "scale" : "2x" 96 | }, 97 | { 98 | "orientation" : "portrait", 99 | "idiom" : "ipad", 100 | "extent" : "full-screen", 101 | "minimum-system-version" : "8.0", 102 | "subtype" : "1366h", 103 | "scale" : "2x" 104 | }, 105 | { 106 | "orientation" : "portrait", 107 | "idiom" : "iphone", 108 | "filename" : "Default-750@2x~iphone6-portrait_750x1334-1.png", 109 | "extent" : "full-screen", 110 | "minimum-system-version" : "7.0", 111 | "scale" : "2x" 112 | }, 113 | { 114 | "extent" : "full-screen", 115 | "idiom" : "iphone", 116 | "subtype" : "retina4", 117 | "filename" : "Default-1242@3x~iphone6s-portrait_1242x2208-1.png", 118 | "minimum-system-version" : "7.0", 119 | "orientation" : "portrait", 120 | "scale" : "2x" 121 | }, 122 | { 123 | "orientation" : "portrait", 124 | "idiom" : "ipad", 125 | "filename" : "Default-Portrait~ipad_768x1024.png", 126 | "extent" : "full-screen", 127 | "minimum-system-version" : "7.0", 128 | "scale" : "1x" 129 | }, 130 | { 131 | "orientation" : "landscape", 132 | "idiom" : "ipad", 133 | "filename" : "Default-Landscape~ipad_1024x768.png", 134 | "extent" : "full-screen", 135 | "minimum-system-version" : "7.0", 136 | "scale" : "1x" 137 | }, 138 | { 139 | "orientation" : "portrait", 140 | "idiom" : "ipad", 141 | "filename" : "Default-Portrait@2x~ipad_1536x2048.png", 142 | "extent" : "full-screen", 143 | "minimum-system-version" : "7.0", 144 | "scale" : "2x" 145 | }, 146 | { 147 | "orientation" : "landscape", 148 | "idiom" : "ipad", 149 | "filename" : "Default-Landscape@2x~ipad_2048x1536.png", 150 | "extent" : "full-screen", 151 | "minimum-system-version" : "7.0", 152 | "scale" : "2x" 153 | } 154 | ], 155 | "info" : { 156 | "version" : 1, 157 | "author" : "xcode" 158 | } 159 | } -------------------------------------------------------------------------------- /iOSMDMAgent/URLUtils.m: -------------------------------------------------------------------------------- 1 | // 2 | // URLUtils.m 3 | // iOSMDMAgent 4 | 5 | 6 | #import "URLUtils.h" 7 | 8 | @implementation URLUtils 9 | 10 | float const HTTP_REQUEST_TIME = 60.0f; 11 | int HTTP_OK = 200; 12 | int HTTP_CREATED = 201; 13 | int OAUTH_FAIL_CODE = 401; 14 | int HTTP_BAD_REQUEST = 400; 15 | NSString *const ENDPOINT_FILE_NAME = @"Endpoints"; 16 | NSString *const EXTENSION = @"plist"; 17 | NSString *const TOKEN_PUBLISH_URI = @"TOKEN_PUBLISH_URI"; 18 | NSString *const ENROLLMENT_URI = @"ENROLLMENT_URI"; 19 | NSString *const OPERATION_URI = @"OPERATION_URI"; 20 | NSString *const LOCATION_PUBLISH_URI = @"LOCATION_PUBLISH_URI"; 21 | NSString *const SERVER_URL = @"SERVER_URL"; 22 | NSString *const CONTEXT_URI = @"SERVER_CONTEXT"; 23 | NSString *const API_PORT = @"API_PORT"; 24 | NSString *const ENROLMENT_PORT = @"ENROLMENT_PORT"; 25 | NSString *const TOKEN = @"token"; 26 | NSString *const GET = @"GET"; 27 | NSString *const POST = @"POST"; 28 | NSString *const PUT = @"PUT"; 29 | NSString *const ACCEPT = @"Accept"; 30 | NSString *const CONTENT_TYPE = @"Content-Type"; 31 | NSString *const APPLICATION_JSON = @"application/json"; 32 | NSString *const LATITIUDE = @"latitude"; 33 | NSString *const LONGITUDE = @"longitude"; 34 | NSString *const UNENROLLMENT_PATH = @"UNENROLLMENT_PATH"; 35 | NSString *const AUTHORIZATION_BASIC = @" Basic "; 36 | NSString *const AUTHORIZATION_BEARER = @" Bearer "; 37 | NSString *const AUTHORIZATION = @"Authorization"; 38 | NSString *const REFRESH_TOKEN_URI =@"REFRESH_TOKEN_URI"; 39 | NSString *const REFRESH_TOKEN_LABEL = @"refresh_token"; 40 | NSString *const GRANT_TYPE = @"grant_type"; 41 | NSString *const GRANT_TYPE_VALUE = @"refresh_token"; 42 | NSString *const FORM_ENCODED = @"application/x-www-form-urlencoded"; 43 | NSString *const OPERATION_ID_RESPOSNE = @"operationId"; 44 | NSString *const STATUS = @"status"; 45 | NSString *const ENROLLMENT_URL = @"ENROLLMENT_URL"; 46 | NSString *const EFFECTIVE_POLICY_PATH = @"EFFECTIVE_POLICY_PATH"; 47 | NSString *const TOKEN_REFRESH_URI = @"TOKEN_REFRESH_URI"; 48 | 49 | 50 | + (NSDictionary *)readEndpoints { 51 | NSString* plistPath = [[NSBundle mainBundle] pathForResource:ENDPOINT_FILE_NAME ofType:EXTENSION]; 52 | return [NSDictionary dictionaryWithContentsOfFile:plistPath]; 53 | } 54 | 55 | + (NSString *)getServerURL { 56 | NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults]; 57 | return [userDefaults objectForKey:SERVER_URL]; 58 | } 59 | 60 | + (NSString *)getContextURL { 61 | return [[URLUtils readEndpoints] objectForKey:CONTEXT_URI]; 62 | } 63 | 64 | + (NSString *)getAPIPort { 65 | return [[URLUtils readEndpoints] objectForKey:API_PORT]; 66 | } 67 | 68 | + (NSString *)getEnrollmentURLFromPlist { 69 | return [[URLUtils readEndpoints] objectForKey:ENROLLMENT_URL]; 70 | } 71 | 72 | + (NSString *)getServerURLFromPlist { 73 | return [[URLUtils readEndpoints] objectForKey:SERVER_URL]; 74 | } 75 | 76 | + (NSString *)getEnrolmentPort { 77 | return [[URLUtils readEndpoints] objectForKey:ENROLMENT_PORT]; 78 | } 79 | 80 | + (NSString *)getSavedEnrollmentURL { 81 | NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults]; 82 | return [userDefaults objectForKey:ENROLLMENT_URL]; 83 | } 84 | 85 | + (void)saveEnrollmentURL:(NSString *)enrollURL { 86 | NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults]; 87 | [userDefaults setObject:enrollURL forKey:ENROLLMENT_URL]; 88 | [userDefaults synchronize]; 89 | } 90 | 91 | + (void)saveServerURL:(NSString *)serverURL { 92 | NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults]; 93 | [userDefaults setObject:serverURL forKey:SERVER_URL]; 94 | [userDefaults synchronize]; 95 | } 96 | 97 | + (NSString *)getTokenPublishURL { 98 | return [NSString stringWithFormat:@"%@:%@%@%@", [URLUtils getServerURL], [URLUtils getAPIPort], [URLUtils getContextURL], [[URLUtils readEndpoints] objectForKey:TOKEN_PUBLISH_URI]]; 99 | } 100 | 101 | + (NSString *)getLocationPublishURL { 102 | return [NSString stringWithFormat:@"%@:%@%@%@", [URLUtils getServerURL], [URLUtils getAPIPort], [URLUtils getContextURL], [[URLUtils readEndpoints] objectForKey:LOCATION_PUBLISH_URI]]; 103 | } 104 | 105 | + (NSString *)getOperationURL { 106 | return [NSString stringWithFormat:@"%@:%@%@%@", [URLUtils getServerURL], [URLUtils getAPIPort], [URLUtils getContextURL], [[URLUtils readEndpoints] objectForKey:OPERATION_URI]]; 107 | } 108 | 109 | + (NSString *)getUnenrollURL { 110 | return [NSString stringWithFormat:@"%@:%@%@%@", [URLUtils getServerURL], [URLUtils getAPIPort], [URLUtils getContextURL], [[URLUtils readEndpoints] objectForKey:UNENROLLMENT_PATH]]; 111 | } 112 | 113 | + (NSString *)getRefreshTokenURL{ 114 | return [NSString stringWithFormat:@"%@:%@%@", [URLUtils getServerURL], [URLUtils getAPIPort], [[URLUtils readEndpoints] objectForKey:REFRESH_TOKEN_URI]]; 115 | } 116 | 117 | + (NSString *)getEnrollmentURL { 118 | return [NSString stringWithFormat:@"%@:%@%@", [URLUtils getSavedEnrollmentURL], [URLUtils getEnrolmentPort], [[URLUtils readEndpoints] objectForKey:ENROLLMENT_URI]]; 119 | } 120 | 121 | + (NSString *)getTokenRefreshURL { 122 | return [NSString stringWithFormat:@"%@:%@%@", [URLUtils getSavedEnrollmentURL], [URLUtils getEnrolmentPort], [[URLUtils readEndpoints] objectForKey:TOKEN_REFRESH_URI]]; 123 | } 124 | 125 | + (NSString *)getEffectivePolicyURL { 126 | return [NSString stringWithFormat:@"%@:%@%@%@", [URLUtils getServerURL], [URLUtils getAPIPort], [URLUtils getContextURL], [[URLUtils readEndpoints] objectForKey:EFFECTIVE_POLICY_PATH]]; 127 | } 128 | 129 | @end 130 | -------------------------------------------------------------------------------- /iOSMDMAgent/MDMUtils.m: -------------------------------------------------------------------------------- 1 | // 2 | // MDMUtils.m 3 | // iOSMDMAgent 4 | // 5 | // Created by Dilshan Edirisuriya on 2/19/15. 6 | // Copyright (c) 2015 WSO2. All rights reserved. 7 | // 8 | 9 | #import "MDMUtils.h" 10 | 11 | #define MINUTE_IN_SECONDS 60 12 | #define HOUR_IN_SECONDS 3600 13 | #define DAY_IN_SECONDS 86400 14 | #define WEEK_IN_SECONDS 604800 15 | #define MONTH_IN_SECONDS 18144000 16 | 17 | @implementation MDMUtils 18 | 19 | int LOCATION_DISTANCE_FILTER = 100; 20 | NSString *const UDID = @"DEVICE_UDID"; 21 | NSString *const APS = @"aps"; 22 | NSString *const EXTRA = @"extra"; 23 | NSString *const OPERATION = @"operation"; 24 | NSString *const OPERATION_ID = @"operationId"; 25 | NSString *const SOUND_FILE_NAME = @"sound"; 26 | NSString *const SOUND_FILE_EXTENSION = @"caf"; 27 | NSString *const ENCLOSING_TAGS = @"<>"; 28 | NSString *const TOKEN_KEYCHAIN = @"TOKEN_KEYCHAIN1"; 29 | NSString *const CLIENT_DETAILS_KEYCHAIN = @"CLIENT_DETAILS_KEYCHAIN"; 30 | NSString *const ENROLL_STATUS = @"ENROLL_STATUS"; 31 | NSString *const ENROLLED = @"enrolled"; 32 | NSString *const UNENROLLED = @"unenrolled"; 33 | NSString *const LOCATION_OPERATION_ID = @"LOCATION_OPERATION_ID"; 34 | NSString *const ACCESS_TOKEN = @"ACCESS_TOKEN"; 35 | NSString *const REFRESH_TOKEN = @"REFRESH_TOKEN"; 36 | NSString *const CLIENT_CREDENTIALS = @"CLIENT_CREDENTIALS"; 37 | NSString *const TENANT_DOMAIN = @"TENANT_DOMAIN"; 38 | NSString *const LOCATION_UPDATED_TIME = @"LOCATION_UPDATED_TIME"; 39 | 40 | + (void)saveDeviceUDID:(NSString *)udid { 41 | NSLog(@"Saving device UUID: %@", udid); 42 | NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults]; 43 | [userDefaults setObject:udid forKey:UDID]; 44 | [userDefaults synchronize]; 45 | } 46 | 47 | + (void)savePreferance:(NSString *)key value:(NSString *)val { 48 | NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults]; 49 | [userDefaults setObject:val forKey:key]; 50 | [userDefaults synchronize]; 51 | } 52 | 53 | + (NSString *)getPreferance:(NSString *)key { 54 | NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults]; 55 | return [userDefaults objectForKey:key]; 56 | } 57 | 58 | + (NSString *)getDeviceUDID { 59 | NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults]; 60 | return [userDefaults objectForKey:UDID]; 61 | } 62 | 63 | + (NSString *) getEnrollStatus { 64 | NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults]; 65 | return [userDefaults objectForKey:ENROLL_STATUS]; 66 | } 67 | 68 | + (void) setEnrollStatus: (NSString *)value { 69 | NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults]; 70 | [userDefaults setObject:value forKey:ENROLL_STATUS]; 71 | [userDefaults synchronize]; 72 | } 73 | 74 | 75 | + (NSString *) getLocationOperationId { 76 | NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults]; 77 | return [userDefaults objectForKey:LOCATION_OPERATION_ID]; 78 | } 79 | 80 | + (void) setLocationOperationId: (NSString *)value { 81 | NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults]; 82 | [userDefaults setObject:value forKey:LOCATION_OPERATION_ID]; 83 | [userDefaults synchronize]; 84 | } 85 | 86 | + (void)setAccessToken:(NSString *)accessToken { 87 | NSLog(@"Saving access token : %@", accessToken); 88 | NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults]; 89 | [userDefaults setObject:accessToken forKey:ACCESS_TOKEN]; 90 | [userDefaults synchronize]; 91 | } 92 | 93 | + (void)setRefreshToken:(NSString *)refreshToken { 94 | NSLog(@"Saving refresh token : %@", refreshToken); 95 | NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults]; 96 | [userDefaults setObject:refreshToken forKey:REFRESH_TOKEN]; 97 | [userDefaults synchronize]; 98 | } 99 | 100 | + (NSString *)getAccessToken { 101 | NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults]; 102 | return [userDefaults objectForKey:ACCESS_TOKEN]; 103 | } 104 | 105 | + (NSString *)getRefreshToken { 106 | NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults]; 107 | return [userDefaults objectForKey:REFRESH_TOKEN]; 108 | } 109 | 110 | + (void)setClientCredentials:(NSString *)clientCredentials { 111 | NSLog(@"Saving client credentials : %@", clientCredentials); 112 | NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults]; 113 | [userDefaults setObject:clientCredentials forKey:CLIENT_CREDENTIALS]; 114 | [userDefaults synchronize]; 115 | } 116 | 117 | + (NSString *)getClientCredentials { 118 | NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults]; 119 | return [userDefaults objectForKey:CLIENT_CREDENTIALS]; 120 | } 121 | 122 | + (void)setTenantDomain:(NSString *)tenantDomain { 123 | NSLog(@"Saving tenant domain : %@", tenantDomain); 124 | NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults]; 125 | [userDefaults setObject:tenantDomain forKey:TENANT_DOMAIN]; 126 | [userDefaults synchronize]; 127 | } 128 | 129 | + (NSString *)getTenantDomain { 130 | NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults]; 131 | return [userDefaults objectForKey:TENANT_DOMAIN]; 132 | } 133 | 134 | + (void)setLocationUpdatedTime { 135 | NSDate* now = [NSDate date]; 136 | NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init]; 137 | [dateFormatter setTimeStyle:NSDateFormatterShortStyle]; 138 | NSString *currentTime = [dateFormatter stringFromDate:now]; 139 | NSLog(@"Saving location updated time : %@", currentTime); 140 | NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults]; 141 | [userDefaults setObject:now forKey:LOCATION_UPDATED_TIME]; 142 | [userDefaults synchronize]; 143 | } 144 | 145 | + (NSString *)getLocationUpdatedTime { 146 | NSLog(@"Getting location updated time"); 147 | NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults]; 148 | NSDate* date1 = [NSDate date]; 149 | NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init]; 150 | [dateFormatter setTimeStyle:NSDateFormatterShortStyle]; 151 | NSString *currentTime = [dateFormatter stringFromDate:date1]; 152 | NSLog(@"Current time : %@", currentTime); 153 | 154 | NSDate* date2 = [userDefaults objectForKey:LOCATION_UPDATED_TIME]; 155 | [dateFormatter setTimeStyle:NSDateFormatterShortStyle]; 156 | currentTime = [dateFormatter stringFromDate:date2]; 157 | NSLog(@"Last updated time : %@", currentTime); 158 | 159 | if (date2 == nil) { 160 | NSLog(@"Location updated time is not available"); 161 | return @"never"; 162 | } 163 | 164 | NSTimeInterval distanceBetweenDates = [date1 timeIntervalSinceDate:date2]; 165 | NSInteger syncTime = distanceBetweenDates/MONTH_IN_SECONDS; 166 | if (syncTime > 0) { 167 | NSLog(@"Getting location updated time from month format"); 168 | return [NSString stringWithFormat:@"%li month(s) ago", (long)syncTime]; 169 | } 170 | syncTime = distanceBetweenDates/WEEK_IN_SECONDS; 171 | if (syncTime > 0) { 172 | NSLog(@"Getting location updated time from week format"); 173 | return [NSString stringWithFormat:@"%li week(s) ago", (long)syncTime]; 174 | } 175 | syncTime = distanceBetweenDates/DAY_IN_SECONDS; 176 | if (syncTime > 0) { 177 | NSLog(@"Getting location updated time from day format"); 178 | return [NSString stringWithFormat:@"%li day(s) ago", (long)syncTime]; 179 | } 180 | syncTime = distanceBetweenDates/MINUTE_IN_SECONDS; 181 | if (syncTime > 0) { 182 | NSLog(@"Getting location updated time from minute format"); 183 | return [NSString stringWithFormat:@"%li minute(s) ago", (long)syncTime]; 184 | } 185 | 186 | NSLog(@"Getting location updated time from seconds format"); 187 | return [NSString stringWithFormat:@"%li second(s) ago", (long)distanceBetweenDates]; 188 | } 189 | 190 | @end 191 | -------------------------------------------------------------------------------- /iOSMDMAgent/KeychainItemWrapper.m: -------------------------------------------------------------------------------- 1 | #import "KeychainItemWrapper.h" 2 | #import 3 | 4 | /* 5 | 6 | These are the default constants and their respective types, 7 | available for the kSecClassGenericPassword Keychain Item class: 8 | 9 | kSecAttrAccessGroup - CFStringRef 10 | kSecAttrCreationDate - CFDateRef 11 | kSecAttrModificationDate - CFDateRef 12 | kSecAttrDescription - CFStringRef 13 | kSecAttrComment - CFStringRef 14 | kSecAttrCreator - CFNumberRef 15 | kSecAttrType - CFNumberRef 16 | kSecAttrLabel - CFStringRef 17 | kSecAttrIsInvisible - CFBooleanRef 18 | kSecAttrIsNegative - CFBooleanRef 19 | kSecAttrAccount - CFStringRef 20 | kSecAttrService - CFStringRef 21 | kSecAttrGeneric - CFDataRef 22 | 23 | See the header file Security/SecItem.h for more details. 24 | 25 | */ 26 | 27 | @interface KeychainItemWrapper (PrivateMethods) 28 | /* 29 | The decision behind the following two methods (secItemFormatToDictionary and dictionaryToSecItemFormat) was 30 | to encapsulate the transition between what the detail view controller was expecting (NSString *) and what the 31 | Keychain API expects as a validly constructed container class. 32 | */ 33 | - (NSMutableDictionary *)secItemFormatToDictionary:(NSDictionary *)dictionaryToConvert; 34 | - (NSMutableDictionary *)dictionaryToSecItemFormat:(NSDictionary *)dictionaryToConvert; 35 | 36 | // Updates the item in the keychain, or adds it if it doesn't exist. 37 | - (void)writeToKeychain; 38 | 39 | @end 40 | 41 | @implementation KeychainItemWrapper 42 | 43 | @synthesize keychainItemData, genericPasswordQuery; 44 | 45 | - (id)initWithIdentifier: (NSString *)identifier accessGroup:(NSString *) accessGroup; 46 | { 47 | if (self = [super init]) 48 | { 49 | // Begin Keychain search setup. The genericPasswordQuery leverages the special user 50 | // defined attribute kSecAttrGeneric to distinguish itself between other generic Keychain 51 | // items which may be included by the same application. 52 | genericPasswordQuery = [[NSMutableDictionary alloc] init]; 53 | 54 | [genericPasswordQuery setObject:(__bridge id)kSecClassGenericPassword forKey:(__bridge id)kSecClass]; 55 | [genericPasswordQuery setObject:identifier forKey:(__bridge id)kSecAttrGeneric]; 56 | 57 | // The keychain access group attribute determines if this item can be shared 58 | // amongst multiple apps whose code signing entitlements contain the same keychain access group. 59 | if (accessGroup != nil) 60 | { 61 | #if TARGET_IPHONE_SIMULATOR 62 | // Ignore the access group if running on the iPhone simulator. 63 | // 64 | // Apps that are built for the simulator aren't signed, so there's no keychain access group 65 | // for the simulator to check. This means that all apps can see all keychain items when run 66 | // on the simulator. 67 | // 68 | // If a SecItem contains an access group attribute, SecItemAdd and SecItemUpdate on the 69 | // simulator will return -25243 (errSecNoAccessForItem). 70 | #else 71 | [genericPasswordQuery setObject:accessGroup forKey:(__bridge id)kSecAttrAccessGroup]; 72 | #endif 73 | } 74 | 75 | // Use the proper search constants, return only the attributes of the first match. 76 | [genericPasswordQuery setObject:(__bridge id)kSecMatchLimitOne forKey:(__bridge id)kSecMatchLimit]; 77 | [genericPasswordQuery setObject:(id)kCFBooleanTrue forKey:(__bridge id)kSecReturnAttributes]; 78 | 79 | NSDictionary *tempQuery = [NSDictionary dictionaryWithDictionary:genericPasswordQuery]; 80 | 81 | NSMutableDictionary *dictionary = nil; 82 | CFTypeRef outDictionary = (__bridge CFTypeRef)dictionary; 83 | 84 | if (! SecItemCopyMatching((__bridge CFDictionaryRef)tempQuery, &outDictionary) == noErr) 85 | { 86 | // Stick these default values into keychain item if nothing found. 87 | [self resetKeychainItem]; 88 | 89 | // Add the generic attribute and the keychain access group. 90 | [keychainItemData setObject:identifier forKey:(__bridge id)kSecAttrGeneric]; 91 | if (accessGroup != nil) 92 | { 93 | #if TARGET_IPHONE_SIMULATOR 94 | // Ignore the access group if running on the iPhone simulator. 95 | // 96 | // Apps that are built for the simulator aren't signed, so there's no keychain access group 97 | // for the simulator to check. This means that all apps can see all keychain items when run 98 | // on the simulator. 99 | // 100 | // If a SecItem contains an access group attribute, SecItemAdd and SecItemUpdate on the 101 | // simulator will return -25243 (errSecNoAccessForItem). 102 | #else 103 | [keychainItemData setObject:accessGroup forKey:(__bridge id)kSecAttrAccessGroup]; 104 | #endif 105 | } 106 | } 107 | else 108 | { 109 | // load the saved data from Keychain. 110 | self.keychainItemData = [self secItemFormatToDictionary:(__bridge NSDictionary *)(outDictionary)]; 111 | } 112 | 113 | //[outDictionary release]; 114 | } 115 | 116 | return self; 117 | } 118 | 119 | 120 | - (void)setObject:(id)inObject forKey:(id)key 121 | { 122 | if (inObject == nil) return; 123 | id currentObject = [keychainItemData objectForKey:key]; 124 | if (![currentObject isEqual:inObject]) 125 | { 126 | [keychainItemData setObject:inObject forKey:key]; 127 | [self writeToKeychain]; 128 | } 129 | } 130 | 131 | - (id)objectForKey:(id)key 132 | { 133 | return [keychainItemData objectForKey:key]; 134 | } 135 | 136 | - (void)resetKeychainItem 137 | { 138 | OSStatus junk = noErr; 139 | if (!keychainItemData) 140 | { 141 | self.keychainItemData = [[NSMutableDictionary alloc] init]; 142 | } 143 | else if (keychainItemData) 144 | { 145 | NSMutableDictionary *tempDictionary = [self dictionaryToSecItemFormat:keychainItemData]; 146 | junk = SecItemDelete((__bridge CFDictionaryRef)tempDictionary); 147 | NSAssert( junk == noErr || junk == errSecItemNotFound, @"Problem deleting current dictionary." ); 148 | } 149 | 150 | // Default attributes for keychain item. 151 | [keychainItemData setObject:@"" forKey:(__bridge id)kSecAttrAccount]; 152 | [keychainItemData setObject:@"" forKey:(__bridge id)kSecAttrLabel]; 153 | [keychainItemData setObject:@"" forKey:(__bridge id)kSecAttrDescription]; 154 | 155 | // Default data for keychain item. 156 | [keychainItemData setObject:@"" forKey:(__bridge id)kSecValueData]; 157 | } 158 | 159 | - (NSMutableDictionary *)dictionaryToSecItemFormat:(NSDictionary *)dictionaryToConvert 160 | { 161 | // The assumption is that this method will be called with a properly populated dictionary 162 | // containing all the right key/value pairs for a SecItem. 163 | 164 | // Create a dictionary to return populated with the attributes and data. 165 | NSMutableDictionary *returnDictionary = [NSMutableDictionary dictionaryWithDictionary:dictionaryToConvert]; 166 | 167 | // Add the Generic Password keychain item class attribute. 168 | [returnDictionary setObject:(__bridge id)kSecClassGenericPassword forKey:(__bridge id)kSecClass]; 169 | 170 | // Convert the NSString to NSData to meet the requirements for the value type kSecValueData. 171 | // This is where to store sensitive data that should be encrypted. 172 | NSString *passwordString = [dictionaryToConvert objectForKey:(__bridge id)kSecValueData]; 173 | [returnDictionary setObject:[passwordString dataUsingEncoding:NSUTF8StringEncoding] forKey:(__bridge id)kSecValueData]; 174 | 175 | return returnDictionary; 176 | } 177 | 178 | - (NSMutableDictionary *)secItemFormatToDictionary:(NSDictionary *)dictionaryToConvert 179 | { 180 | // The assumption is that this method will be called with a properly populated dictionary 181 | // containing all the right key/value pairs for the UI element. 182 | 183 | // Create a dictionary to return populated with the attributes and data. 184 | NSMutableDictionary *returnDictionary = [NSMutableDictionary dictionaryWithDictionary:dictionaryToConvert]; 185 | 186 | // Add the proper search key and class attribute. 187 | [returnDictionary setObject:(id)kCFBooleanTrue forKey:(__bridge id)kSecReturnData]; 188 | [returnDictionary setObject:(__bridge id)kSecClassGenericPassword forKey:(__bridge id)kSecClass]; 189 | 190 | // Acquire the password data from the attributes. 191 | NSData *pData = NULL; 192 | CFTypeRef passwordData = (__bridge CFTypeRef)pData; 193 | if (SecItemCopyMatching((__bridge CFDictionaryRef)returnDictionary, &passwordData) == noErr) 194 | { 195 | // Remove the search, class, and identifier key/value, we don't need them anymore. 196 | [returnDictionary removeObjectForKey:(__bridge id)kSecReturnData]; 197 | 198 | NSData *resultData = CFBridgingRelease(passwordData); 199 | // Add the password to the dictionary, converting from NSData to NSString. 200 | //NSString *password = [[[NSString alloc] initWithBytes:[passwordData bytes] length:[passwordData length] 201 | //encoding:NSUTF8StringEncoding] autorelease]; 202 | NSString *password = [[NSString alloc] initWithData:resultData encoding:NSUTF8StringEncoding]; 203 | [returnDictionary setObject:password forKey:(__bridge id)kSecValueData]; 204 | } 205 | else 206 | { 207 | // Don't do anything if nothing is found. 208 | NSAssert(NO, @"Serious error, no matching item found in the keychain.\n"); 209 | } 210 | 211 | //[passwordData release]; 212 | 213 | return returnDictionary; 214 | } 215 | 216 | - (void)writeToKeychain 217 | { 218 | NSDictionary *attr = NULL; 219 | CFTypeRef attributes = (__bridge CFTypeRef)attr; 220 | NSMutableDictionary *updateItem = NULL; 221 | OSStatus result; 222 | 223 | if (SecItemCopyMatching((__bridge CFDictionaryRef)genericPasswordQuery, (CFTypeRef *)&attributes) == noErr) 224 | { 225 | // First we need the attributes from the Keychain. 226 | updateItem = [NSMutableDictionary dictionaryWithDictionary:(__bridge NSDictionary *)(attributes)]; 227 | // Second we need to add the appropriate search key/values. 228 | [updateItem setObject:[genericPasswordQuery objectForKey:(__bridge id)kSecClass] forKey:(__bridge id)kSecClass]; 229 | 230 | // Lastly, we need to set up the updated attribute list being careful to remove the class. 231 | NSMutableDictionary *tempCheck = [self dictionaryToSecItemFormat:keychainItemData]; 232 | [tempCheck removeObjectForKey:(__bridge id)kSecClass]; 233 | 234 | #if TARGET_IPHONE_SIMULATOR 235 | // Remove the access group if running on the iPhone simulator. 236 | // 237 | // Apps that are built for the simulator aren't signed, so there's no keychain access group 238 | // for the simulator to check. This means that all apps can see all keychain items when run 239 | // on the simulator. 240 | // 241 | // If a SecItem contains an access group attribute, SecItemAdd and SecItemUpdate on the 242 | // simulator will return -25243 (errSecNoAccessForItem). 243 | // 244 | // The access group attribute will be included in items returned by SecItemCopyMatching, 245 | // which is why we need to remove it before updating the item. 246 | [tempCheck removeObjectForKey:(__bridge id)kSecAttrAccessGroup]; 247 | #endif 248 | 249 | // An implicit assumption is that you can only update a single item at a time. 250 | 251 | result = SecItemUpdate((__bridge CFDictionaryRef)updateItem, (__bridge CFDictionaryRef)tempCheck); 252 | NSAssert( result == noErr, @"Couldn't update the Keychain Item." ); 253 | } 254 | else 255 | { 256 | // No previous item found; add the new one. 257 | result = SecItemAdd((__bridge CFDictionaryRef)[self dictionaryToSecItemFormat:keychainItemData], NULL); 258 | NSAssert( result == noErr, @"Couldn't add the Keychain Item." ); 259 | } 260 | } 261 | 262 | @end -------------------------------------------------------------------------------- /iOSMDMAgent/ConnectionUtils.m: -------------------------------------------------------------------------------- 1 | // 2 | // ConnectionUtils.m 3 | // iOSMDMAgent 4 | // 5 | 6 | #import "ConnectionUtils.h" 7 | #import "URLUtils.h" 8 | #import "MDMUtils.h" 9 | #import "AppDelegate.h" 10 | 11 | //Remove this code chunk in production 12 | @interface NSURLRequest(Private) 13 | 14 | +(void)setAllowsAnyHTTPSCertificate:(BOOL)inAllow forHost:(NSString *)inHost; 15 | 16 | @end 17 | 18 | @implementation ConnectionUtils 19 | 20 | - (void)sendPushTokenToServer:(NSString *)udid pushToken:(NSString *)token { 21 | 22 | NSString *endpoint = [NSString stringWithFormat:[URLUtils getTokenPublishURL], udid]; 23 | 24 | NSURL *url = [NSURL URLWithString:endpoint]; 25 | NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:HTTP_REQUEST_TIME]; 26 | NSLog(@"sendPushTokenToServer:url: %@", url); 27 | NSMutableDictionary *paramDictionary = [[NSMutableDictionary alloc] init]; 28 | [paramDictionary setValue:token forKey:TOKEN]; 29 | 30 | [request setHTTPMethod:PUT]; 31 | [request setHTTPBody:[[self dictionaryToJSON:paramDictionary] dataUsingEncoding:NSUTF8StringEncoding]]; 32 | [self setContentType:request]; 33 | [self addAccessToken:request]; 34 | 35 | [self setAllowsAnyHTTPSCertificate:url]; 36 | [NSURLConnection sendAsynchronousRequest:request queue:[[NSOperationQueue alloc] init] completionHandler:^(NSURLResponse *response, NSData *data, NSError *error) { 37 | long code = [(NSHTTPURLResponse *)response statusCode]; 38 | NSString *returnedData = [[NSString alloc]initWithData:data encoding:NSUTF8StringEncoding]; 39 | if (returnedData != nil) { 40 | NSLog(@"sendPushTokenToServer:Data recieved: %@", returnedData); 41 | } 42 | 43 | NSLog(@"sendPushTokenToServer:Response recieved: %ld", code); 44 | if (code == OAUTH_FAIL_CODE || code == 0) { 45 | NSLog(@"Authentication failed. Obtaining a new access token"); 46 | if([self getNewAccessToken]){ 47 | [self sendPushTokenToServer:udid pushToken:token]; 48 | } 49 | NSLog(@"Error occurred %ld", code); 50 | } 51 | 52 | }]; 53 | } 54 | 55 | - (void)enforceEffectivePolicy:(NSString *)deviceId { 56 | 57 | NSString *endpoint = [NSString stringWithFormat:[URLUtils getEffectivePolicyURL], deviceId]; 58 | NSLog(@"enforceEffectivePolicy:endpoint: %@", endpoint); 59 | 60 | NSURL *url = [NSURL URLWithString:endpoint]; 61 | NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:HTTP_REQUEST_TIME]; 62 | 63 | [request setHTTPMethod:GET]; 64 | [self setContentType:request]; 65 | [self addAccessToken:request]; 66 | 67 | [self setAllowsAnyHTTPSCertificate:url]; 68 | [NSURLConnection sendAsynchronousRequest:request queue:[[NSOperationQueue alloc] init] completionHandler:^(NSURLResponse *response, NSData *data, NSError *error) { 69 | long code = [(NSHTTPURLResponse *)response statusCode]; 70 | NSString *returnedData = [[NSString alloc]initWithData:data encoding:NSUTF8StringEncoding]; 71 | if (returnedData != nil) { 72 | NSLog(@"enforceEffectivePolicy:Data recieved: %@", returnedData); 73 | } 74 | 75 | NSLog(@"enforceEffectivePolicy:Response recieved: %ld", code); 76 | if (code == OAUTH_FAIL_CODE || code == 0) { 77 | NSLog(@"Authentication failed. Obtaining a new access token"); 78 | if([self getNewAccessToken]){ 79 | [self enforceEffectivePolicy:deviceId]; 80 | } 81 | NSLog(@"Error occurred %ld", code); 82 | } 83 | }]; 84 | } 85 | 86 | - (void)sendLocationToServer:(NSString *)udid latitiude:(float)lat longitude:(float)longi { 87 | NSString *endpoint = [NSString stringWithFormat:[URLUtils getLocationPublishURL], udid]; 88 | 89 | NSURL *url = [NSURL URLWithString:endpoint]; 90 | NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:HTTP_REQUEST_TIME]; 91 | 92 | NSMutableDictionary *paramDictionary = [[NSMutableDictionary alloc] init]; 93 | [paramDictionary setObject:[NSNumber numberWithFloat:lat] forKey:LATITIUDE]; 94 | [paramDictionary setObject:[NSNumber numberWithFloat:longi] forKey:LONGITUDE]; 95 | [paramDictionary setObject:[MDMUtils getLocationOperationId] forKey:OPERATION_ID]; 96 | 97 | [request setHTTPMethod:PUT]; 98 | [request setHTTPBody:[[self dictionaryToJSON:paramDictionary] dataUsingEncoding:NSUTF8StringEncoding]]; 99 | [self setContentType:request]; 100 | 101 | [self addAccessToken:request]; 102 | [self setAllowsAnyHTTPSCertificate:url]; 103 | [NSURLConnection sendAsynchronousRequest:request queue:[[NSOperationQueue alloc] init] completionHandler:^(NSURLResponse *response, NSData *data, NSError *error) { 104 | long code = [(NSHTTPURLResponse *)response statusCode]; 105 | 106 | NSString *returnedData = [[NSString alloc]initWithData:data encoding:NSUTF8StringEncoding]; 107 | if (returnedData != nil) { 108 | NSLog(@"sendLocationUpdateToServer:Data recieved: %@", returnedData); 109 | [MDMUtils setLocationUpdatedTime]; 110 | } 111 | 112 | NSLog(@"sendLocationToServer:Response recieved: %ld", code); 113 | if (code == OAUTH_FAIL_CODE || code == 0) { 114 | NSLog(@"Authentication failed. Obtaining a new access token"); 115 | if([self getNewAccessToken]){ 116 | [self sendLocationToServer:udid latitiude:lat longitude:longi]; 117 | } 118 | NSLog(@"Error occurred %ld", code); 119 | } 120 | }]; 121 | } 122 | 123 | 124 | - (void)sendOperationUpdateToServer:(NSString *)deviceId operationId:(NSString *)opId status:(NSString *)state { 125 | NSString *endpoint = [NSString stringWithFormat:[URLUtils getOperationURL], deviceId]; 126 | 127 | NSURL *url = [NSURL URLWithString:endpoint]; 128 | NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:HTTP_REQUEST_TIME]; 129 | 130 | NSMutableDictionary *paramDictionary = [[NSMutableDictionary alloc] init]; 131 | [paramDictionary setValue:opId forKey:OPERATION_ID]; 132 | [paramDictionary setValue:state forKey:STATUS]; 133 | 134 | [request setHTTPMethod:PUT]; 135 | [request setHTTPBody:[[self dictionaryToJSON:paramDictionary] dataUsingEncoding:NSUTF8StringEncoding]]; 136 | [self setContentType:request]; 137 | 138 | [self addAccessToken:request]; 139 | [self setAllowsAnyHTTPSCertificate:url]; 140 | [NSURLConnection sendAsynchronousRequest:request queue:[[NSOperationQueue alloc] init] completionHandler:^(NSURLResponse *response, NSData *data, NSError *error) { 141 | long code = [(NSHTTPURLResponse *)response statusCode]; 142 | 143 | NSString *returnedData = [[NSString alloc]initWithData:data encoding:NSUTF8StringEncoding]; 144 | if (returnedData != nil) { 145 | NSLog(@"sendOperationUpdateToServer:Data recieved: %@", returnedData); 146 | } 147 | NSLog(@"sendOperationUpdateToServer:Response recieved: %ld", code); 148 | if (code == OAUTH_FAIL_CODE || code == 0) { 149 | NSLog(@"Authentication failed. Obtaining a new access token"); 150 | if([self getNewAccessToken]){ 151 | [self sendOperationUpdateToServer:deviceId operationId:opId status:state]; 152 | } 153 | NSLog(@"Error occurred %ld", code); 154 | } 155 | }]; 156 | } 157 | 158 | - (void)sendUnenrollToServer { 159 | [self getNewAccessToken]; 160 | NSURL *url = [NSURL URLWithString:[URLUtils getUnenrollURL]]; 161 | 162 | NSString *deviceId = [MDMUtils getDeviceUDID]; 163 | NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:HTTP_REQUEST_TIME]; 164 | NSArray *deviceList = @[deviceId]; 165 | 166 | [request setHTTPMethod:POST]; 167 | [self addAccessToken:request]; 168 | [request setHTTPBody:[[self arrayToJSON:deviceList] dataUsingEncoding:NSUTF8StringEncoding]]; 169 | [self setContentType:request]; 170 | 171 | [self setAllowsAnyHTTPSCertificate:url]; 172 | [NSURLConnection sendAsynchronousRequest:request queue:[[NSOperationQueue alloc] init] completionHandler:^(NSURLResponse *response, NSData *data, NSError *error) { 173 | long code = [(NSHTTPURLResponse *)response statusCode]; 174 | NSString *returnedData = [[NSString alloc]initWithData:data encoding:NSUTF8StringEncoding]; 175 | if (returnedData != nil) { 176 | NSLog(@"sendUnenrollToServer:Data recieved: %@", returnedData); 177 | } 178 | NSLog(@"sendUnenrollToServer:Response recieved: %ld", code); 179 | if (code == OAUTH_FAIL_CODE) { 180 | NSLog(@"Authentication failed. Obtaining a new access token"); 181 | if([self getNewAccessToken]){ 182 | [self sendUnenrollToServer]; 183 | } 184 | [MDMUtils setEnrollStatus:UNENROLLED]; 185 | 186 | } else if (code == HTTP_CREATED) { 187 | 188 | if([_delegate respondsToSelector:@selector(unregisterSuccessful)]){ 189 | [_delegate unregisterSuccessful]; 190 | } 191 | 192 | } else { 193 | 194 | if([_delegate respondsToSelector:@selector(unregisterFailure:)]){ 195 | [_delegate unregisterFailure:error]; 196 | } 197 | 198 | } 199 | }]; 200 | } 201 | 202 | - (void)addAccessToken:(NSMutableURLRequest *)request { 203 | NSString *storedAccessToken = [MDMUtils getPreferance:ACCESS_TOKEN]; 204 | 205 | if(storedAccessToken != nil){ 206 | NSString *headerValue = [AUTHORIZATION_BEARER stringByAppendingString:storedAccessToken]; 207 | [request setValue:headerValue forHTTPHeaderField:AUTHORIZATION]; 208 | } 209 | } 210 | 211 | 212 | - (BOOL)getNewAccessToken { 213 | 214 | NSLog(@"getNewAccessToken: Obtaining a new access token"); 215 | 216 | NSString *endpoint = [URLUtils getRefreshTokenURL]; 217 | 218 | NSURL *url = [NSURL URLWithString:endpoint]; 219 | NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:HTTP_REQUEST_TIME]; 220 | NSMutableDictionary *paramDictionary = [[NSMutableDictionary alloc] init]; 221 | 222 | 223 | NSString *storedRefreshToken = [MDMUtils getPreferance:REFRESH_TOKEN]; 224 | 225 | if(storedRefreshToken != nil){ 226 | [paramDictionary setObject:storedRefreshToken forKey:REFRESH_TOKEN_LABEL]; 227 | } 228 | 229 | [paramDictionary setObject:GRANT_TYPE_VALUE forKey:GRANT_TYPE]; 230 | [paramDictionary setObject:@"PRODUCTION" forKey:@"scope"]; 231 | 232 | NSString *payload=[@"grant_type=refresh_token&refresh_token=" stringByAppendingString:storedRefreshToken]; 233 | [request setHTTPMethod:POST]; 234 | [request setHTTPBody:[payload dataUsingEncoding:NSUTF8StringEncoding]]; 235 | [self setContentTypeFormEncoded:request]; 236 | [self addClientDeatils:request]; 237 | [self setAllowsAnyHTTPSCertificate:url]; 238 | 239 | NSURLResponse * response = nil; 240 | NSError * error = nil; 241 | NSData * data = [NSURLConnection sendSynchronousRequest:request 242 | returningResponse:&response 243 | error:&error]; 244 | long code = [(NSHTTPURLResponse *)response statusCode]; 245 | 246 | if (error == nil) 247 | { 248 | NSLog(@"getNewAccessToken:Response recieved: %li", code); 249 | if (code == HTTP_OK) { 250 | NSError *jsonError; 251 | NSString *returnedData = [[NSString alloc]initWithData:data encoding:NSUTF8StringEncoding]; 252 | NSData *objectData = [returnedData dataUsingEncoding:NSUTF8StringEncoding]; 253 | NSDictionary *json = [NSJSONSerialization JSONObjectWithData:objectData 254 | options:NSJSONReadingMutableContainers 255 | error:&jsonError]; 256 | NSString *accessToken =(NSString*)[json objectForKey:@"access_token"]; 257 | NSString *refreshToken =(NSString*)[json objectForKey:@"refresh_token"]; 258 | 259 | [MDMUtils savePreferance:ACCESS_TOKEN value:accessToken]; 260 | [MDMUtils savePreferance:REFRESH_TOKEN value:refreshToken]; 261 | 262 | return true; 263 | } 264 | } 265 | if (code == HTTP_BAD_REQUEST) { 266 | NSLog(@"Refresh token expired."); 267 | [[UIApplication sharedApplication] openURL:[NSURL URLWithString:[URLUtils getTokenRefreshURL]]]; 268 | } 269 | NSLog(@"Error while getting refresh token."); 270 | return false; 271 | } 272 | 273 | - (void)addClientDeatils:(NSMutableURLRequest *)request { 274 | 275 | NSString *storedClientDetails = [MDMUtils getPreferance:CLIENT_CREDENTIALS]; 276 | 277 | if(storedClientDetails != nil){ 278 | NSString *headerValue = [AUTHORIZATION_BASIC stringByAppendingString:storedClientDetails]; 279 | [request setValue:headerValue forHTTPHeaderField:AUTHORIZATION]; 280 | } 281 | } 282 | 283 | - (void)setContentType:(NSMutableURLRequest *)request { 284 | [request setValue:APPLICATION_JSON forHTTPHeaderField:CONTENT_TYPE]; 285 | [request setValue:APPLICATION_JSON forHTTPHeaderField:ACCEPT]; 286 | } 287 | 288 | - (void)setContentTypeFormEncoded:(NSMutableURLRequest *)request { 289 | [request setValue:FORM_ENCODED forHTTPHeaderField:CONTENT_TYPE]; 290 | } 291 | 292 | 293 | - (void)setAllowsAnyHTTPSCertificate:(NSURL *)url { 294 | //remove this code chunk in production 295 | [NSURLRequest setAllowsAnyHTTPSCertificate:YES forHost:[url host]]; 296 | } 297 | 298 | -(NSString *)dictionaryToJSON:(NSDictionary *)dictionary { 299 | NSData *jsonData = [NSJSONSerialization dataWithJSONObject:dictionary options:NSJSONWritingPrettyPrinted error:nil]; 300 | return [[NSString alloc] initWithBytes:[jsonData bytes] length:[jsonData length] encoding:NSUTF8StringEncoding]; 301 | } 302 | 303 | -(NSString *)arrayToJSON:(NSArray *)array { 304 | NSData *jsonData = [NSJSONSerialization dataWithJSONObject:array options:NSJSONWritingPrettyPrinted error:nil]; 305 | return [[NSString alloc] initWithBytes:[jsonData bytes] length:[jsonData length] encoding:NSUTF8StringEncoding]; 306 | } 307 | 308 | 309 | 310 | @end 311 | -------------------------------------------------------------------------------- /iOSMDMAgent/AppDelegate.m: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.m 3 | // iOSMDMAgent 4 | // 5 | 6 | #import "AppDelegate.h" 7 | #import "MDMUtils.h" 8 | #import "ConnectionUtils.h" 9 | #import "ConnectionUtils.h" 10 | #import "URLUtils.h" 11 | #import 12 | 13 | #define systemSoundID 1154 14 | #define SYSTEM_VERSION_LESS_THAN(v) ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] == NSOrderedAscending) 15 | 16 | @interface AppDelegate () 17 | 18 | @property (nonatomic, copy) void (^fetchCompletionHandler)(UIBackgroundFetchResult result); 19 | 20 | @end 21 | 22 | @implementation AppDelegate 23 | 24 | NSInteger const LOCATION_OFF_CODE = 1000; 25 | 26 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { 27 | 28 | NSLog(@"App is starting..."); 29 | 30 | _connectionUtils = [[ConnectionUtils alloc] init]; 31 | _connectionUtils.delegate = self; 32 | 33 | // Check for iOS 8. Without this guard the code will crash with "unknown selector" on iOS 7. 34 | if ([self.locationManager respondsToSelector:@selector(requestAlwaysAuthorization)]) { 35 | [self.locationManager requestAlwaysAuthorization]; 36 | } 37 | 38 | NSLog(@"Authorizing location service"); 39 | [self authorizeLocationService]; 40 | 41 | NSString *enrollURL = [URLUtils getEnrollmentURLFromPlist]; 42 | NSString *serverURL = [URLUtils getServerURLFromPlist]; 43 | if(enrollURL && ![@"" isEqualToString:enrollURL] && serverURL && ![@"" isEqualToString:serverURL]) { 44 | NSLog(@"Reading server url from plist"); 45 | [URLUtils saveServerURL:serverURL]; 46 | [URLUtils saveEnrollmentURL:enrollURL]; 47 | } 48 | 49 | // Remote configs for the App are pushed by the EMM server and are written to a config space 50 | // with the key com.apple.configuration.managed. 51 | static NSString const *managedConfigurations = @"com.apple.configuration.managed"; 52 | NSDictionary *serverConfig = [[NSUserDefaults standardUserDefaults] dictionaryForKey:managedConfigurations]; 53 | Boolean depEnabled = [[serverConfig objectForKey:@"depEnabled"] boolValue]; 54 | if (depEnabled && ![[MDMUtils getEnrollStatus] isEqualToString:ENROLLED]) { 55 | NSLog(@"DEP enabled device."); 56 | NSString *accessToken = serverConfig[@"accessToken"]; 57 | NSString *refreshToken = serverConfig[@"refreshToken"]; 58 | NSString *clientId = serverConfig[@"clientId"]; 59 | NSString *clientSecret = serverConfig[@"clientSecret"]; 60 | NSString *remoteEnrollmentURL = serverConfig[@"enrollmentURL"]; 61 | NSString *remoteServerURL = serverConfig[@"serverURL"]; 62 | NSString *UDID = serverConfig[@"UDID"]; 63 | NSString *joinCredentials = [NSString stringWithFormat:@"%@:%@", clientId, clientSecret]; 64 | NSData *credentialsData = [joinCredentials dataUsingEncoding:NSUTF8StringEncoding]; 65 | NSString *base64EncodedClientCredentials = [credentialsData base64EncodedStringWithOptions:0]; 66 | [MDMUtils savePreferance:CLIENT_CREDENTIALS value:base64EncodedClientCredentials]; 67 | [MDMUtils savePreferance:ACCESS_TOKEN value:accessToken]; 68 | [MDMUtils savePreferance:REFRESH_TOKEN value:refreshToken]; 69 | NSString *enrollURL = [URLUtils getEnrollmentURLFromPlist]; 70 | [MDMUtils saveDeviceUDID:UDID]; 71 | NSString *serverURL = [URLUtils getServerURLFromPlist]; 72 | if(enrollURL && ![@"" isEqualToString:enrollURL] && serverURL && ![@"" isEqualToString:serverURL]) { 73 | NSLog(@"Agent contains embedded values."); 74 | [URLUtils saveServerURL:serverURL]; 75 | [URLUtils saveEnrollmentURL:enrollURL]; 76 | }else { 77 | NSLog(@"Agent is using remote configs."); 78 | NSString *remoteServerURLHTTPS = [NSString stringWithFormat:@"https://%@", remoteServerURL]; 79 | NSString *remoteEnrollmentURLHTTPS = [NSString stringWithFormat:@"https://%@", remoteEnrollmentURL]; 80 | [URLUtils saveServerURL:remoteServerURLHTTPS]; 81 | [URLUtils saveEnrollmentURL:remoteEnrollmentURLHTTPS]; 82 | } 83 | NSLog(@"DEP config initiated."); 84 | [self registerForPushToken]; 85 | [MDMUtils setEnrollStatus:ENROLLED]; 86 | [self showLoginViewController]; 87 | } 88 | 89 | return YES; 90 | } 91 | 92 | - (void)applicationWillResignActive:(UIApplication *)application { 93 | // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. 94 | // Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game. 95 | } 96 | 97 | - (void)applicationDidEnterBackground:(UIApplication *)application { 98 | // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. 99 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. 100 | } 101 | 102 | - (void)applicationWillEnterForeground:(UIApplication *)application { 103 | // Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background. 104 | } 105 | 106 | - (void)applicationDidBecomeActive:(UIApplication *)application { 107 | // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. 108 | if ([[MDMUtils getEnrollStatus] isEqualToString:ENROLLED]) { 109 | [self showUnregisterViewController]; 110 | } 111 | } 112 | 113 | - (void)applicationWillTerminate:(UIApplication *)application { 114 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. 115 | } 116 | 117 | - (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult result))completionHandler { 118 | 119 | self.fetchCompletionHandler = completionHandler; 120 | NSDictionary *apsDictionary = [userInfo objectForKey:APS]; 121 | NSDictionary *extraDictionary = [userInfo objectForKey:EXTRA]; 122 | NSString *udid = [MDMUtils getDeviceUDID]; 123 | NSLog(@"Notification recieved to device: %@", udid); 124 | 125 | if (apsDictionary) { 126 | if (extraDictionary && [extraDictionary isKindOfClass:[NSDictionary class]]) { 127 | 128 | NSString *operation = [extraDictionary objectForKey:OPERATION]; 129 | NSString *operationId = [extraDictionary objectForKey:OPERATION_ID]; 130 | 131 | NSLog(@"Received operation: %@", operation); 132 | NSLog(@"Operation id: %@", operationId); 133 | 134 | if ([@"RING" isEqualToString:operation]) { 135 | [self triggerAlert]; 136 | ConnectionUtils *connectionUtils = [[ConnectionUtils alloc] init]; 137 | connectionUtils.delegate = self; 138 | [connectionUtils sendOperationUpdateToServer:udid operationId:operationId status:@"COMPLETED"]; 139 | 140 | } else if([@"DEVICE_LOCATION" isEqualToString:operation]) { 141 | [MDMUtils setLocationOperationId:operationId]; 142 | NSLog(@"Location commmand, Time Remaining: %f", [[UIApplication sharedApplication] backgroundTimeRemaining]); 143 | [self initLocation]; 144 | } 145 | } 146 | } 147 | } 148 | 149 | - (void)application:(UIApplication*)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData*)deviceToken { 150 | 151 | NSLog(@"Sending push token to the server"); 152 | //Check if the UDID is stored 153 | NSString *udid = [MDMUtils getDeviceUDID]; 154 | 155 | if (udid) { 156 | //Device is register in the server 157 | NSString *token = [[[deviceToken description] stringByTrimmingCharactersInSet:[NSCharacterSet characterSetWithCharactersInString:ENCLOSING_TAGS]] stringByReplacingOccurrencesOfString:@" " withString:@""]; 158 | 159 | if (token) { 160 | 161 | NSLog(@"Device Token: %@", token); 162 | 163 | NSString *oldToken = [MDMUtils getDeviceUDID]; 164 | if (!oldToken || ![oldToken isEqualToString:token]) { 165 | 166 | //push the token to the server 167 | [_connectionUtils sendPushTokenToServer:udid pushToken:token]; 168 | } 169 | } 170 | } 171 | } 172 | 173 | - (void)application:(UIApplication*)application didFailToRegisterForRemoteNotificationsWithError:(NSError*)error { 174 | NSLog(@"Failed to get token, error: %@", error); 175 | } 176 | 177 | - (BOOL) application:(UIApplication *)application handleOpenURL:(NSURL *)url { 178 | NSLog(@"handleOpenURL:Decoding URL"); 179 | NSString *accessToken; 180 | NSString *refreshToken; 181 | NSString *clientCredentials; 182 | NSString *tenantDomain; 183 | NSString *isRefreshComplete; 184 | 185 | NSArray *queryParams = [[url query] componentsSeparatedByString:@"&"]; 186 | for (int i=0; i< [queryParams count]; i++){ 187 | NSArray *keyValue = [queryParams[i] componentsSeparatedByString:@"="]; 188 | NSString *key = keyValue[0]; 189 | NSString *value = keyValue[1]; 190 | if([key isEqualToString:@"accessToken"]){ 191 | accessToken = value; 192 | } 193 | else if([key isEqualToString:@"refreshToken"]){ 194 | refreshToken = value; 195 | } 196 | else if([key isEqualToString:@"clientCredentials"]){ 197 | clientCredentials = value; 198 | } 199 | else if ([key isEqualToString:@"tenantDomain"]) { 200 | tenantDomain = value; 201 | } 202 | else if ([key isEqualToString:@"isRefreshComplete"]) { 203 | isRefreshComplete = value; 204 | } 205 | } 206 | 207 | 208 | [MDMUtils savePreferance:ACCESS_TOKEN value:accessToken]; 209 | [MDMUtils savePreferance:REFRESH_TOKEN value:refreshToken]; 210 | [MDMUtils savePreferance:CLIENT_CREDENTIALS value:clientCredentials]; 211 | 212 | if (!isRefreshComplete) { 213 | NSLog(@"New enrollment"); 214 | NSString *udid = [[url host] stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding]; 215 | [MDMUtils saveDeviceUDID:udid]; 216 | [self registerForPushToken]; 217 | [MDMUtils setEnrollStatus:ENROLLED]; 218 | NSLog(@"handleOpenURL:Enforcing effective policy"); 219 | ConnectionUtils *connectionUtils = [[ConnectionUtils alloc] init]; 220 | connectionUtils.delegate = self; 221 | [connectionUtils enforceEffectivePolicy:[MDMUtils getDeviceUDID]]; 222 | } 223 | return YES; 224 | } 225 | 226 | - (void)showLoginViewController { 227 | UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@"Main" bundle:nil]; 228 | UIViewController *loginViewController = [storyboard instantiateViewControllerWithIdentifier:@"loginViewController"]; 229 | UIViewController *top = [UIApplication sharedApplication].keyWindow.rootViewController; 230 | loginViewController.modalPresentationStyle = UIModalPresentationFullScreen; 231 | [top presentViewController:loginViewController animated:NO completion:nil]; 232 | } 233 | 234 | - (void)showUnregisterViewController { 235 | UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@"Main" bundle:nil]; 236 | UIViewController *unregisterViewController = [storyboard instantiateViewControllerWithIdentifier:@"viewController"]; 237 | UIViewController *top = [UIApplication sharedApplication].keyWindow.rootViewController; 238 | unregisterViewController.modalPresentationStyle = UIModalPresentationFullScreen; 239 | [top presentViewController:unregisterViewController animated:NO completion:nil]; 240 | } 241 | 242 | - (void) registerForPushToken { 243 | 244 | NSLog(@"Registering for push token"); 245 | 246 | UIApplication *application = [UIApplication sharedApplication]; 247 | if ([application respondsToSelector:@selector(isRegisteredForRemoteNotifications)]) { 248 | // iOS 8 Notifications 249 | [application registerUserNotificationSettings:[UIUserNotificationSettings settingsForTypes:(UIUserNotificationTypeSound | UIUserNotificationTypeAlert | UIUserNotificationTypeBadge) categories:nil]]; 250 | 251 | [application registerForRemoteNotifications]; 252 | } else { 253 | // iOS < 8 Notifications 254 | [application registerForRemoteNotificationTypes:(UIRemoteNotificationTypeBadge | UIRemoteNotificationTypeAlert | UIRemoteNotificationTypeSound)]; 255 | } 256 | } 257 | 258 | - (void)locationManager:(CLLocationManager *)manager didChangeAuthorizationStatus:(CLAuthorizationStatus)status { 259 | NSLog(@"didChangeAuthorizationStatus"); 260 | if ([CLLocationManager locationServicesEnabled]) { 261 | if ([self.locationManager respondsToSelector:@selector(requestAlwaysAuthorization)]) { 262 | [self authorizeLocationService]; 263 | } 264 | } 265 | } 266 | 267 | - (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex { 268 | if(alertView.tag && LOCATION_OFF_CODE == alertView.tag) { 269 | NSLog(@"Opening location settings"); 270 | NSString* url = SYSTEM_VERSION_LESS_THAN(@"10.0") ? 271 | @"prefs:root=LOCATION_SERVICES" : @"App-Prefs:root=Privacy&path=LOCATION"; 272 | [[UIApplication sharedApplication] openURL:[NSURL URLWithString: url]]; 273 | } else { 274 | if(buttonIndex == 1) { 275 | [[UIApplication sharedApplication] openURL:[NSURL URLWithString:UIApplicationOpenSettingsURLString]]; 276 | } 277 | } 278 | } 279 | -(CLLocationManager *)locationManager { 280 | if(_locationManager) { 281 | return _locationManager; 282 | } 283 | 284 | CLLocationManager *manager = [[CLLocationManager alloc] init]; 285 | _locationManager = manager; 286 | 287 | _locationManager.delegate = self; 288 | _locationManager.desiredAccuracy = kCLLocationAccuracyKilometer; 289 | _locationManager.pausesLocationUpdatesAutomatically = NO; 290 | _locationManager.allowsBackgroundLocationUpdates = YES; 291 | _locationManager.distanceFilter = kCLDistanceFilterNone;// Any movement change 292 | if (@available(iOS 11.0, *)) { 293 | _locationManager.showsBackgroundLocationIndicator = NO; //Hiding the location Update screen from user 294 | } 295 | return _locationManager; 296 | } 297 | 298 | 299 | - (void)initLocation { 300 | NSLog(@"Initializing location manager"); 301 | [self.locationManager startUpdatingLocation]; 302 | } 303 | 304 | - (void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error 305 | { 306 | NSLog(@"Calling didFailWithError %@", [error localizedDescription]); 307 | if (self.fetchCompletionHandler) { 308 | self.fetchCompletionHandler(UIBackgroundFetchResultFailed); 309 | self.fetchCompletionHandler = nil; 310 | } 311 | } 312 | 313 | - (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations { 314 | [self.locationManager stopUpdatingLocation]; 315 | NSLog(@"Sending location updates to the server"); 316 | NSString *udid = [MDMUtils getDeviceUDID]; 317 | CLLocation *location = [locations lastObject]; 318 | 319 | if (location && udid) { 320 | [_connectionUtils sendLocationToServer:udid latitiude:location.coordinate.latitude longitude:location.coordinate.longitude]; 321 | } 322 | dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(10 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ 323 | if (self.fetchCompletionHandler) { 324 | self.fetchCompletionHandler(UIBackgroundFetchResultNewData); 325 | self.fetchCompletionHandler = nil; 326 | } 327 | }); 328 | } 329 | 330 | - (void)triggerAlert { 331 | //initializing sound files 332 | NSLog(@"Start ringing the device"); 333 | NSString *soundPath =[[NSBundle mainBundle] pathForResource:SOUND_FILE_NAME ofType:SOUND_FILE_EXTENSION]; 334 | NSURL *soundURL = [NSURL fileURLWithPath:soundPath]; 335 | 336 | /** 337 | * iOS does not natively provide a way to update volume of a devices without users consent. 338 | * Since MPMusicPlayerController.volume is depricated, we have to use the following 339 | * work around, where we create a volume slider and adjust the volume. 340 | */ 341 | MPVolumeView* mpVolumeView = [[MPVolumeView alloc] init]; 342 | UISlider* volumeSlider = nil; 343 | for (UIView *view in [mpVolumeView subviews]){ 344 | if ([view.class.description isEqualToString:@"MPVolumeSlider"]){ 345 | volumeSlider = (UISlider*)view; 346 | break; 347 | } 348 | } 349 | [volumeSlider setValue:1.0f animated:YES]; 350 | [volumeSlider sendActionsForControlEvents:UIControlEventTouchUpInside]; 351 | 352 | NSError *error = nil; 353 | self.theAudio = [[AVAudioPlayer alloc] initWithContentsOfURL:soundURL error:&error]; 354 | [[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayback 355 | withOptions:AVAudioSessionCategoryOptionMixWithOthers error:nil]; 356 | [[AVAudioSession sharedInstance] setActive: YES error: nil]; 357 | [[UIApplication sharedApplication] beginReceivingRemoteControlEvents]; 358 | [self.theAudio play]; 359 | 360 | } 361 | 362 | - (void)authorizeLocationService { 363 | switch (CLLocationManager.authorizationStatus) { 364 | case kCLAuthorizationStatusNotDetermined: 365 | NSLog(@"Location authorization status: not determined"); 366 | [self.locationManager requestAlwaysAuthorization]; 367 | break; 368 | 369 | case kCLAuthorizationStatusRestricted: 370 | NSLog(@"Location authorization status: restricted"); 371 | [self.locationManager requestAlwaysAuthorization]; 372 | break; 373 | 374 | case kCLAuthorizationStatusDenied: 375 | NSLog(@"Location authorization status: denied"); 376 | [self.locationManager requestAlwaysAuthorization]; 377 | break; 378 | 379 | case kCLAuthorizationStatusAuthorizedWhenInUse: 380 | NSLog(@"Location authorization status: authorized when in use"); 381 | [self.locationManager requestAlwaysAuthorization]; 382 | break; 383 | 384 | case kCLAuthorizationStatusAuthorizedAlways: 385 | NSLog(@"Location authorization status: authorized always"); 386 | // Nothing to do here 387 | break; 388 | } 389 | } 390 | 391 | @end 392 | -------------------------------------------------------------------------------- /iOSMDMAgent/Base.lproj/Main.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 51 | 70 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | -------------------------------------------------------------------------------- /iOSMDMAgent.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 142143961A9600BD006C34B6 /* MDMUtils.m in Sources */ = {isa = PBXBuildFile; fileRef = 142143951A9600BD006C34B6 /* MDMUtils.m */; }; 11 | 142143991A96021B006C34B6 /* MDMConstants.m in Sources */ = {isa = PBXBuildFile; fileRef = 142143981A96021B006C34B6 /* MDMConstants.m */; }; 12 | 144CAA801AC2B6E7006AB191 /* AVFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 144CAA7F1AC2B6E7006AB191 /* AVFoundation.framework */; }; 13 | 144CAA821AC2B96D006AB191 /* sound.caf in Resources */ = {isa = PBXBuildFile; fileRef = 144CAA811AC2B96D006AB191 /* sound.caf */; }; 14 | 144CAA841AC2C001006AB191 /* AudioToolbox.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 144CAA831AC2C001006AB191 /* AudioToolbox.framework */; }; 15 | 14AE5F5C1AC034B0005144D3 /* ConnectionUtils.m in Sources */ = {isa = PBXBuildFile; fileRef = 14AE5F5B1AC034B0005144D3 /* ConnectionUtils.m */; }; 16 | 14AE5F5E1AC03509005144D3 /* Endpoints.plist in Resources */ = {isa = PBXBuildFile; fileRef = 14AE5F5D1AC03509005144D3 /* Endpoints.plist */; }; 17 | 14AE5F611AC035C4005144D3 /* URLUtils.m in Sources */ = {isa = PBXBuildFile; fileRef = 14AE5F601AC035C4005144D3 /* URLUtils.m */; }; 18 | 14AE5F631AC039EC005144D3 /* CFNetwork.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 14AE5F621AC039EC005144D3 /* CFNetwork.framework */; }; 19 | 14AE5F661AC282C1005144D3 /* CoreLocation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 14AE5F651AC282C1005144D3 /* CoreLocation.framework */; }; 20 | 14BD722E1A83479900D43DE5 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 14BD722D1A83479900D43DE5 /* main.m */; }; 21 | 14BD72311A83479900D43DE5 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 14BD72301A83479900D43DE5 /* AppDelegate.m */; }; 22 | 14BD72341A83479900D43DE5 /* ViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 14BD72331A83479900D43DE5 /* ViewController.m */; }; 23 | 14BD72371A83479900D43DE5 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 14BD72351A83479900D43DE5 /* Main.storyboard */; }; 24 | 14BD72391A83479900D43DE5 /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 14BD72381A83479900D43DE5 /* Images.xcassets */; }; 25 | 14BD723C1A83479900D43DE5 /* LaunchScreen.xib in Resources */ = {isa = PBXBuildFile; fileRef = 14BD723A1A83479900D43DE5 /* LaunchScreen.xib */; }; 26 | 14BD72481A83479900D43DE5 /* iOSMDMAgentTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 14BD72471A83479900D43DE5 /* iOSMDMAgentTests.m */; }; 27 | 14BD72541A834E2200D43DE5 /* LoginViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 14BD72531A834E2200D43DE5 /* LoginViewController.m */; }; 28 | E80C7E3C2040137100215441 /* ManagedAppConfig.plist in Resources */ = {isa = PBXBuildFile; fileRef = E80C7E3B2040137100215441 /* ManagedAppConfig.plist */; }; 29 | /* End PBXBuildFile section */ 30 | 31 | /* Begin PBXContainerItemProxy section */ 32 | 14BD72421A83479900D43DE5 /* PBXContainerItemProxy */ = { 33 | isa = PBXContainerItemProxy; 34 | containerPortal = 14BD72201A83479800D43DE5 /* Project object */; 35 | proxyType = 1; 36 | remoteGlobalIDString = 14BD72271A83479800D43DE5; 37 | remoteInfo = iOSMDMAgent; 38 | }; 39 | /* End PBXContainerItemProxy section */ 40 | 41 | /* Begin PBXFileReference section */ 42 | 142143941A9600BD006C34B6 /* MDMUtils.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MDMUtils.h; sourceTree = ""; }; 43 | 142143951A9600BD006C34B6 /* MDMUtils.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MDMUtils.m; sourceTree = ""; }; 44 | 142143971A96021B006C34B6 /* MDMConstants.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MDMConstants.h; sourceTree = ""; }; 45 | 142143981A96021B006C34B6 /* MDMConstants.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MDMConstants.m; sourceTree = ""; }; 46 | 1434B47B1C219BB800EEEBC4 /* SDKProtocol.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SDKProtocol.h; sourceTree = ""; }; 47 | 144CAA7F1AC2B6E7006AB191 /* AVFoundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AVFoundation.framework; path = System/Library/Frameworks/AVFoundation.framework; sourceTree = SDKROOT; }; 48 | 144CAA811AC2B96D006AB191 /* sound.caf */ = {isa = PBXFileReference; lastKnownFileType = file; name = sound.caf; path = sound/sound.caf; sourceTree = ""; }; 49 | 144CAA831AC2C001006AB191 /* AudioToolbox.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AudioToolbox.framework; path = System/Library/Frameworks/AudioToolbox.framework; sourceTree = SDKROOT; }; 50 | 14AE5F5A1AC034B0005144D3 /* ConnectionUtils.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ConnectionUtils.h; sourceTree = ""; }; 51 | 14AE5F5B1AC034B0005144D3 /* ConnectionUtils.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ConnectionUtils.m; sourceTree = ""; }; 52 | 14AE5F5D1AC03509005144D3 /* Endpoints.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Endpoints.plist; sourceTree = ""; }; 53 | 14AE5F5F1AC035C4005144D3 /* URLUtils.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = URLUtils.h; sourceTree = ""; }; 54 | 14AE5F601AC035C4005144D3 /* URLUtils.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = URLUtils.m; sourceTree = ""; }; 55 | 14AE5F621AC039EC005144D3 /* CFNetwork.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CFNetwork.framework; path = System/Library/Frameworks/CFNetwork.framework; sourceTree = SDKROOT; }; 56 | 14AE5F651AC282C1005144D3 /* CoreLocation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreLocation.framework; path = System/Library/Frameworks/CoreLocation.framework; sourceTree = SDKROOT; }; 57 | 14BD72281A83479800D43DE5 /* iOSMDMAgent.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = iOSMDMAgent.app; sourceTree = BUILT_PRODUCTS_DIR; }; 58 | 14BD722C1A83479800D43DE5 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 59 | 14BD722D1A83479900D43DE5 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 60 | 14BD722F1A83479900D43DE5 /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; 61 | 14BD72301A83479900D43DE5 /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; 62 | 14BD72321A83479900D43DE5 /* ViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ViewController.h; sourceTree = ""; }; 63 | 14BD72331A83479900D43DE5 /* ViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ViewController.m; sourceTree = ""; }; 64 | 14BD72361A83479900D43DE5 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 65 | 14BD72381A83479900D43DE5 /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = ""; }; 66 | 14BD723B1A83479900D43DE5 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/LaunchScreen.xib; sourceTree = ""; }; 67 | 14BD72411A83479900D43DE5 /* iOSMDMAgentTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = iOSMDMAgentTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 68 | 14BD72461A83479900D43DE5 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 69 | 14BD72471A83479900D43DE5 /* iOSMDMAgentTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = iOSMDMAgentTests.m; sourceTree = ""; }; 70 | 14BD72521A834E2200D43DE5 /* LoginViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LoginViewController.h; sourceTree = ""; }; 71 | 14BD72531A834E2200D43DE5 /* LoginViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = LoginViewController.m; sourceTree = ""; }; 72 | 40735CED1D9BC4CA00AAB802 /* iOSMDMAgent.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = iOSMDMAgent.entitlements; sourceTree = ""; }; 73 | E80C7E3B2040137100215441 /* ManagedAppConfig.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = ManagedAppConfig.plist; path = ManagedAppConfig.plist; sourceTree = ""; }; 74 | /* End PBXFileReference section */ 75 | 76 | /* Begin PBXFrameworksBuildPhase section */ 77 | 14BD72251A83479800D43DE5 /* Frameworks */ = { 78 | isa = PBXFrameworksBuildPhase; 79 | buildActionMask = 2147483647; 80 | files = ( 81 | 144CAA841AC2C001006AB191 /* AudioToolbox.framework in Frameworks */, 82 | 144CAA801AC2B6E7006AB191 /* AVFoundation.framework in Frameworks */, 83 | 14AE5F661AC282C1005144D3 /* CoreLocation.framework in Frameworks */, 84 | 14AE5F631AC039EC005144D3 /* CFNetwork.framework in Frameworks */, 85 | ); 86 | runOnlyForDeploymentPostprocessing = 0; 87 | }; 88 | 14BD723E1A83479900D43DE5 /* Frameworks */ = { 89 | isa = PBXFrameworksBuildPhase; 90 | buildActionMask = 2147483647; 91 | files = ( 92 | ); 93 | runOnlyForDeploymentPostprocessing = 0; 94 | }; 95 | /* End PBXFrameworksBuildPhase section */ 96 | 97 | /* Begin PBXGroup section */ 98 | 142143931A96009B006C34B6 /* SDK */ = { 99 | isa = PBXGroup; 100 | children = ( 101 | 142143941A9600BD006C34B6 /* MDMUtils.h */, 102 | 142143951A9600BD006C34B6 /* MDMUtils.m */, 103 | 142143971A96021B006C34B6 /* MDMConstants.h */, 104 | 142143981A96021B006C34B6 /* MDMConstants.m */, 105 | 14AE5F5F1AC035C4005144D3 /* URLUtils.h */, 106 | 14AE5F601AC035C4005144D3 /* URLUtils.m */, 107 | 14AE5F5A1AC034B0005144D3 /* ConnectionUtils.h */, 108 | 14AE5F5B1AC034B0005144D3 /* ConnectionUtils.m */, 109 | 1434B47B1C219BB800EEEBC4 /* SDKProtocol.h */, 110 | ); 111 | name = SDK; 112 | sourceTree = ""; 113 | }; 114 | 14AE5F641AC039FC005144D3 /* Libraries */ = { 115 | isa = PBXGroup; 116 | children = ( 117 | 144CAA831AC2C001006AB191 /* AudioToolbox.framework */, 118 | 144CAA7F1AC2B6E7006AB191 /* AVFoundation.framework */, 119 | 14AE5F651AC282C1005144D3 /* CoreLocation.framework */, 120 | 14AE5F621AC039EC005144D3 /* CFNetwork.framework */, 121 | ); 122 | name = Libraries; 123 | sourceTree = ""; 124 | }; 125 | 14BD721F1A83479800D43DE5 = { 126 | isa = PBXGroup; 127 | children = ( 128 | 14BD722A1A83479800D43DE5 /* iOSMDMAgent */, 129 | 14BD72441A83479900D43DE5 /* iOSMDMAgentTests */, 130 | 14BD72291A83479800D43DE5 /* Products */, 131 | 400698A41DACD866003B5C07 /* Frameworks */, 132 | ); 133 | sourceTree = ""; 134 | }; 135 | 14BD72291A83479800D43DE5 /* Products */ = { 136 | isa = PBXGroup; 137 | children = ( 138 | 14BD72281A83479800D43DE5 /* iOSMDMAgent.app */, 139 | 14BD72411A83479900D43DE5 /* iOSMDMAgentTests.xctest */, 140 | ); 141 | name = Products; 142 | sourceTree = ""; 143 | }; 144 | 14BD722A1A83479800D43DE5 /* iOSMDMAgent */ = { 145 | isa = PBXGroup; 146 | children = ( 147 | E80C7E3B2040137100215441 /* ManagedAppConfig.plist */, 148 | 40735CED1D9BC4CA00AAB802 /* iOSMDMAgent.entitlements */, 149 | 142143931A96009B006C34B6 /* SDK */, 150 | 14BD722F1A83479900D43DE5 /* AppDelegate.h */, 151 | 14BD72301A83479900D43DE5 /* AppDelegate.m */, 152 | 14BD72321A83479900D43DE5 /* ViewController.h */, 153 | 14BD72331A83479900D43DE5 /* ViewController.m */, 154 | 14BD72521A834E2200D43DE5 /* LoginViewController.h */, 155 | 14BD72531A834E2200D43DE5 /* LoginViewController.m */, 156 | 14AE5F641AC039FC005144D3 /* Libraries */, 157 | 14BD72511A83488D00D43DE5 /* Views */, 158 | 14BD722B1A83479800D43DE5 /* Supporting Files */, 159 | ); 160 | path = iOSMDMAgent; 161 | sourceTree = ""; 162 | }; 163 | 14BD722B1A83479800D43DE5 /* Supporting Files */ = { 164 | isa = PBXGroup; 165 | children = ( 166 | 14AE5F5D1AC03509005144D3 /* Endpoints.plist */, 167 | 144CAA811AC2B96D006AB191 /* sound.caf */, 168 | 14BD72381A83479900D43DE5 /* Images.xcassets */, 169 | 14BD722C1A83479800D43DE5 /* Info.plist */, 170 | 14BD722D1A83479900D43DE5 /* main.m */, 171 | ); 172 | name = "Supporting Files"; 173 | sourceTree = ""; 174 | }; 175 | 14BD72441A83479900D43DE5 /* iOSMDMAgentTests */ = { 176 | isa = PBXGroup; 177 | children = ( 178 | 14BD72471A83479900D43DE5 /* iOSMDMAgentTests.m */, 179 | 14BD72451A83479900D43DE5 /* Supporting Files */, 180 | ); 181 | path = iOSMDMAgentTests; 182 | sourceTree = ""; 183 | }; 184 | 14BD72451A83479900D43DE5 /* Supporting Files */ = { 185 | isa = PBXGroup; 186 | children = ( 187 | 14BD72461A83479900D43DE5 /* Info.plist */, 188 | ); 189 | name = "Supporting Files"; 190 | sourceTree = ""; 191 | }; 192 | 14BD72511A83488D00D43DE5 /* Views */ = { 193 | isa = PBXGroup; 194 | children = ( 195 | 14BD72351A83479900D43DE5 /* Main.storyboard */, 196 | 14BD723A1A83479900D43DE5 /* LaunchScreen.xib */, 197 | ); 198 | name = Views; 199 | sourceTree = ""; 200 | }; 201 | 400698A41DACD866003B5C07 /* Frameworks */ = { 202 | isa = PBXGroup; 203 | children = ( 204 | ); 205 | name = Frameworks; 206 | sourceTree = ""; 207 | }; 208 | /* End PBXGroup section */ 209 | 210 | /* Begin PBXNativeTarget section */ 211 | 14BD72271A83479800D43DE5 /* iOSMDMAgent */ = { 212 | isa = PBXNativeTarget; 213 | buildConfigurationList = 14BD724B1A83479900D43DE5 /* Build configuration list for PBXNativeTarget "iOSMDMAgent" */; 214 | buildPhases = ( 215 | 14BD72241A83479800D43DE5 /* Sources */, 216 | 14BD72251A83479800D43DE5 /* Frameworks */, 217 | 14BD72261A83479800D43DE5 /* Resources */, 218 | ); 219 | buildRules = ( 220 | ); 221 | dependencies = ( 222 | ); 223 | name = iOSMDMAgent; 224 | productName = iOSMDMAgent; 225 | productReference = 14BD72281A83479800D43DE5 /* iOSMDMAgent.app */; 226 | productType = "com.apple.product-type.application"; 227 | }; 228 | 14BD72401A83479900D43DE5 /* iOSMDMAgentTests */ = { 229 | isa = PBXNativeTarget; 230 | buildConfigurationList = 14BD724E1A83479900D43DE5 /* Build configuration list for PBXNativeTarget "iOSMDMAgentTests" */; 231 | buildPhases = ( 232 | 14BD723D1A83479900D43DE5 /* Sources */, 233 | 14BD723E1A83479900D43DE5 /* Frameworks */, 234 | 14BD723F1A83479900D43DE5 /* Resources */, 235 | ); 236 | buildRules = ( 237 | ); 238 | dependencies = ( 239 | 14BD72431A83479900D43DE5 /* PBXTargetDependency */, 240 | ); 241 | name = iOSMDMAgentTests; 242 | productName = iOSMDMAgentTests; 243 | productReference = 14BD72411A83479900D43DE5 /* iOSMDMAgentTests.xctest */; 244 | productType = "com.apple.product-type.bundle.unit-test"; 245 | }; 246 | /* End PBXNativeTarget section */ 247 | 248 | /* Begin PBXProject section */ 249 | 14BD72201A83479800D43DE5 /* Project object */ = { 250 | isa = PBXProject; 251 | attributes = { 252 | LastUpgradeCheck = 0800; 253 | ORGANIZATIONNAME = WSO2; 254 | TargetAttributes = { 255 | 14BD72271A83479800D43DE5 = { 256 | CreatedOnToolsVersion = 6.1.1; 257 | DevelopmentTeam = KED4SHKL8S; 258 | ProvisioningStyle = Automatic; 259 | SystemCapabilities = { 260 | com.apple.BackgroundModes = { 261 | enabled = 1; 262 | }; 263 | com.apple.GameCenter = { 264 | enabled = 0; 265 | }; 266 | com.apple.Push = { 267 | enabled = 1; 268 | }; 269 | }; 270 | }; 271 | 14BD72401A83479900D43DE5 = { 272 | CreatedOnToolsVersion = 6.1.1; 273 | DevelopmentTeam = KED4SHKL8S; 274 | TestTargetID = 14BD72271A83479800D43DE5; 275 | }; 276 | }; 277 | }; 278 | buildConfigurationList = 14BD72231A83479800D43DE5 /* Build configuration list for PBXProject "iOSMDMAgent" */; 279 | compatibilityVersion = "Xcode 3.2"; 280 | developmentRegion = English; 281 | hasScannedForEncodings = 0; 282 | knownRegions = ( 283 | en, 284 | Base, 285 | ); 286 | mainGroup = 14BD721F1A83479800D43DE5; 287 | productRefGroup = 14BD72291A83479800D43DE5 /* Products */; 288 | projectDirPath = ""; 289 | projectRoot = ""; 290 | targets = ( 291 | 14BD72271A83479800D43DE5 /* iOSMDMAgent */, 292 | 14BD72401A83479900D43DE5 /* iOSMDMAgentTests */, 293 | ); 294 | }; 295 | /* End PBXProject section */ 296 | 297 | /* Begin PBXResourcesBuildPhase section */ 298 | 14BD72261A83479800D43DE5 /* Resources */ = { 299 | isa = PBXResourcesBuildPhase; 300 | buildActionMask = 2147483647; 301 | files = ( 302 | 14BD72371A83479900D43DE5 /* Main.storyboard in Resources */, 303 | 14AE5F5E1AC03509005144D3 /* Endpoints.plist in Resources */, 304 | E80C7E3C2040137100215441 /* ManagedAppConfig.plist in Resources */, 305 | 144CAA821AC2B96D006AB191 /* sound.caf in Resources */, 306 | 14BD723C1A83479900D43DE5 /* LaunchScreen.xib in Resources */, 307 | 14BD72391A83479900D43DE5 /* Images.xcassets in Resources */, 308 | ); 309 | runOnlyForDeploymentPostprocessing = 0; 310 | }; 311 | 14BD723F1A83479900D43DE5 /* Resources */ = { 312 | isa = PBXResourcesBuildPhase; 313 | buildActionMask = 2147483647; 314 | files = ( 315 | ); 316 | runOnlyForDeploymentPostprocessing = 0; 317 | }; 318 | /* End PBXResourcesBuildPhase section */ 319 | 320 | /* Begin PBXSourcesBuildPhase section */ 321 | 14BD72241A83479800D43DE5 /* Sources */ = { 322 | isa = PBXSourcesBuildPhase; 323 | buildActionMask = 2147483647; 324 | files = ( 325 | 142143991A96021B006C34B6 /* MDMConstants.m in Sources */, 326 | 14AE5F611AC035C4005144D3 /* URLUtils.m in Sources */, 327 | 14AE5F5C1AC034B0005144D3 /* ConnectionUtils.m in Sources */, 328 | 14BD72541A834E2200D43DE5 /* LoginViewController.m in Sources */, 329 | 142143961A9600BD006C34B6 /* MDMUtils.m in Sources */, 330 | 14BD72341A83479900D43DE5 /* ViewController.m in Sources */, 331 | 14BD72311A83479900D43DE5 /* AppDelegate.m in Sources */, 332 | 14BD722E1A83479900D43DE5 /* main.m in Sources */, 333 | ); 334 | runOnlyForDeploymentPostprocessing = 0; 335 | }; 336 | 14BD723D1A83479900D43DE5 /* Sources */ = { 337 | isa = PBXSourcesBuildPhase; 338 | buildActionMask = 2147483647; 339 | files = ( 340 | 14BD72481A83479900D43DE5 /* iOSMDMAgentTests.m in Sources */, 341 | ); 342 | runOnlyForDeploymentPostprocessing = 0; 343 | }; 344 | /* End PBXSourcesBuildPhase section */ 345 | 346 | /* Begin PBXTargetDependency section */ 347 | 14BD72431A83479900D43DE5 /* PBXTargetDependency */ = { 348 | isa = PBXTargetDependency; 349 | target = 14BD72271A83479800D43DE5 /* iOSMDMAgent */; 350 | targetProxy = 14BD72421A83479900D43DE5 /* PBXContainerItemProxy */; 351 | }; 352 | /* End PBXTargetDependency section */ 353 | 354 | /* Begin PBXVariantGroup section */ 355 | 14BD72351A83479900D43DE5 /* Main.storyboard */ = { 356 | isa = PBXVariantGroup; 357 | children = ( 358 | 14BD72361A83479900D43DE5 /* Base */, 359 | ); 360 | name = Main.storyboard; 361 | sourceTree = ""; 362 | }; 363 | 14BD723A1A83479900D43DE5 /* LaunchScreen.xib */ = { 364 | isa = PBXVariantGroup; 365 | children = ( 366 | 14BD723B1A83479900D43DE5 /* Base */, 367 | ); 368 | name = LaunchScreen.xib; 369 | sourceTree = ""; 370 | }; 371 | /* End PBXVariantGroup section */ 372 | 373 | /* Begin XCBuildConfiguration section */ 374 | 14BD72491A83479900D43DE5 /* Debug */ = { 375 | isa = XCBuildConfiguration; 376 | buildSettings = { 377 | ALWAYS_SEARCH_USER_PATHS = NO; 378 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 379 | CLANG_CXX_LIBRARY = "libc++"; 380 | CLANG_ENABLE_MODULES = YES; 381 | CLANG_ENABLE_OBJC_ARC = YES; 382 | CLANG_WARN_BOOL_CONVERSION = YES; 383 | CLANG_WARN_CONSTANT_CONVERSION = YES; 384 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 385 | CLANG_WARN_EMPTY_BODY = YES; 386 | CLANG_WARN_ENUM_CONVERSION = YES; 387 | CLANG_WARN_INFINITE_RECURSION = YES; 388 | CLANG_WARN_INT_CONVERSION = YES; 389 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 390 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 391 | CLANG_WARN_UNREACHABLE_CODE = YES; 392 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 393 | CODE_SIGN_IDENTITY = "iPhone Distribution: WSO2 Inc"; 394 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution: WSO2 Inc"; 395 | COPY_PHASE_STRIP = NO; 396 | ENABLE_STRICT_OBJC_MSGSEND = YES; 397 | ENABLE_TESTABILITY = YES; 398 | GCC_C_LANGUAGE_STANDARD = gnu99; 399 | GCC_DYNAMIC_NO_PIC = NO; 400 | GCC_NO_COMMON_BLOCKS = YES; 401 | GCC_OPTIMIZATION_LEVEL = 0; 402 | GCC_PREPROCESSOR_DEFINITIONS = ( 403 | "DEBUG=1", 404 | "$(inherited)", 405 | ); 406 | GCC_SYMBOLS_PRIVATE_EXTERN = NO; 407 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 408 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 409 | GCC_WARN_UNDECLARED_SELECTOR = YES; 410 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 411 | GCC_WARN_UNUSED_FUNCTION = YES; 412 | GCC_WARN_UNUSED_VARIABLE = YES; 413 | IPHONEOS_DEPLOYMENT_TARGET = 6.0; 414 | MTL_ENABLE_DEBUG_INFO = YES; 415 | ONLY_ACTIVE_ARCH = YES; 416 | SDKROOT = iphoneos; 417 | TARGETED_DEVICE_FAMILY = "1,2"; 418 | }; 419 | name = Debug; 420 | }; 421 | 14BD724A1A83479900D43DE5 /* Release */ = { 422 | isa = XCBuildConfiguration; 423 | buildSettings = { 424 | ALWAYS_SEARCH_USER_PATHS = NO; 425 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 426 | CLANG_CXX_LIBRARY = "libc++"; 427 | CLANG_ENABLE_MODULES = YES; 428 | CLANG_ENABLE_OBJC_ARC = YES; 429 | CLANG_WARN_BOOL_CONVERSION = YES; 430 | CLANG_WARN_CONSTANT_CONVERSION = YES; 431 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 432 | CLANG_WARN_EMPTY_BODY = YES; 433 | CLANG_WARN_ENUM_CONVERSION = YES; 434 | CLANG_WARN_INFINITE_RECURSION = YES; 435 | CLANG_WARN_INT_CONVERSION = YES; 436 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 437 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 438 | CLANG_WARN_UNREACHABLE_CODE = YES; 439 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 440 | CODE_SIGN_IDENTITY = "iPhone Distribution: WSO2 Inc"; 441 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution: WSO2 Inc"; 442 | COPY_PHASE_STRIP = YES; 443 | ENABLE_NS_ASSERTIONS = NO; 444 | ENABLE_STRICT_OBJC_MSGSEND = YES; 445 | GCC_C_LANGUAGE_STANDARD = gnu99; 446 | GCC_NO_COMMON_BLOCKS = YES; 447 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 448 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 449 | GCC_WARN_UNDECLARED_SELECTOR = YES; 450 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 451 | GCC_WARN_UNUSED_FUNCTION = YES; 452 | GCC_WARN_UNUSED_VARIABLE = YES; 453 | IPHONEOS_DEPLOYMENT_TARGET = 6.0; 454 | MTL_ENABLE_DEBUG_INFO = NO; 455 | SDKROOT = iphoneos; 456 | TARGETED_DEVICE_FAMILY = "1,2"; 457 | VALIDATE_PRODUCT = YES; 458 | }; 459 | name = Release; 460 | }; 461 | 14BD724C1A83479900D43DE5 /* Debug */ = { 462 | isa = XCBuildConfiguration; 463 | buildSettings = { 464 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 465 | CODE_SIGN_ENTITLEMENTS = iOSMDMAgent/iOSMDMAgent.entitlements; 466 | CODE_SIGN_IDENTITY = "iPhone Distribution: WSO2 Inc"; 467 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 468 | CODE_SIGN_STYLE = Automatic; 469 | DEVELOPMENT_TEAM = ""; 470 | INFOPLIST_FILE = iOSMDMAgent/Info.plist; 471 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 472 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 473 | PRODUCT_BUNDLE_IDENTIFIER = org.wso2.carbon.emm.ios.agent; 474 | PRODUCT_NAME = "$(TARGET_NAME)"; 475 | PROVISIONING_PROFILE = ""; 476 | PROVISIONING_PROFILE_SPECIFIER = ""; 477 | TARGETED_DEVICE_FAMILY = "1,2"; 478 | }; 479 | name = Debug; 480 | }; 481 | 14BD724D1A83479900D43DE5 /* Release */ = { 482 | isa = XCBuildConfiguration; 483 | buildSettings = { 484 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 485 | CODE_SIGN_ENTITLEMENTS = iOSMDMAgent/iOSMDMAgent.entitlements; 486 | CODE_SIGN_IDENTITY = "iPhone Distribution: WSO2 Inc"; 487 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 488 | CODE_SIGN_STYLE = Automatic; 489 | DEVELOPMENT_TEAM = ""; 490 | INFOPLIST_FILE = iOSMDMAgent/Info.plist; 491 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 492 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 493 | PRODUCT_BUNDLE_IDENTIFIER = org.wso2.carbon.emm.ios.agent; 494 | PRODUCT_NAME = "$(TARGET_NAME)"; 495 | PROVISIONING_PROFILE = ""; 496 | PROVISIONING_PROFILE_SPECIFIER = ""; 497 | TARGETED_DEVICE_FAMILY = "1,2"; 498 | }; 499 | name = Release; 500 | }; 501 | 14BD724F1A83479900D43DE5 /* Debug */ = { 502 | isa = XCBuildConfiguration; 503 | buildSettings = { 504 | BUNDLE_LOADER = "$(TEST_HOST)"; 505 | CODE_SIGN_IDENTITY = "iPhone Developer"; 506 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 507 | FRAMEWORK_SEARCH_PATHS = ( 508 | "$(SDKROOT)/Developer/Library/Frameworks", 509 | "$(inherited)", 510 | ); 511 | GCC_PREPROCESSOR_DEFINITIONS = ( 512 | "DEBUG=1", 513 | "$(inherited)", 514 | ); 515 | INFOPLIST_FILE = iOSMDMAgentTests/Info.plist; 516 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 517 | PRODUCT_BUNDLE_IDENTIFIER = "org.wso2.carbon.mdm.mobileservices.ios.agent.$(PRODUCT_NAME:rfc1034identifier)"; 518 | PRODUCT_NAME = "$(TARGET_NAME)"; 519 | PROVISIONING_PROFILE = ""; 520 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/iOSMDMAgent.app/iOSMDMAgent"; 521 | }; 522 | name = Debug; 523 | }; 524 | 14BD72501A83479900D43DE5 /* Release */ = { 525 | isa = XCBuildConfiguration; 526 | buildSettings = { 527 | BUNDLE_LOADER = "$(TEST_HOST)"; 528 | CODE_SIGN_IDENTITY = "iPhone Developer"; 529 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 530 | FRAMEWORK_SEARCH_PATHS = ( 531 | "$(SDKROOT)/Developer/Library/Frameworks", 532 | "$(inherited)", 533 | ); 534 | INFOPLIST_FILE = iOSMDMAgentTests/Info.plist; 535 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 536 | PRODUCT_BUNDLE_IDENTIFIER = "org.wso2.carbon.mdm.mobileservices.ios.agent.$(PRODUCT_NAME:rfc1034identifier)"; 537 | PRODUCT_NAME = "$(TARGET_NAME)"; 538 | PROVISIONING_PROFILE = ""; 539 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/iOSMDMAgent.app/iOSMDMAgent"; 540 | }; 541 | name = Release; 542 | }; 543 | /* End XCBuildConfiguration section */ 544 | 545 | /* Begin XCConfigurationList section */ 546 | 14BD72231A83479800D43DE5 /* Build configuration list for PBXProject "iOSMDMAgent" */ = { 547 | isa = XCConfigurationList; 548 | buildConfigurations = ( 549 | 14BD72491A83479900D43DE5 /* Debug */, 550 | 14BD724A1A83479900D43DE5 /* Release */, 551 | ); 552 | defaultConfigurationIsVisible = 0; 553 | defaultConfigurationName = Release; 554 | }; 555 | 14BD724B1A83479900D43DE5 /* Build configuration list for PBXNativeTarget "iOSMDMAgent" */ = { 556 | isa = XCConfigurationList; 557 | buildConfigurations = ( 558 | 14BD724C1A83479900D43DE5 /* Debug */, 559 | 14BD724D1A83479900D43DE5 /* Release */, 560 | ); 561 | defaultConfigurationIsVisible = 0; 562 | defaultConfigurationName = Release; 563 | }; 564 | 14BD724E1A83479900D43DE5 /* Build configuration list for PBXNativeTarget "iOSMDMAgentTests" */ = { 565 | isa = XCConfigurationList; 566 | buildConfigurations = ( 567 | 14BD724F1A83479900D43DE5 /* Debug */, 568 | 14BD72501A83479900D43DE5 /* Release */, 569 | ); 570 | defaultConfigurationIsVisible = 0; 571 | defaultConfigurationName = Release; 572 | }; 573 | /* End XCConfigurationList section */ 574 | }; 575 | rootObject = 14BD72201A83479800D43DE5 /* Project object */; 576 | } 577 | --------------------------------------------------------------------------------