Device manager

// FREEBIE
pull/1/head
Michael Kirk 9 years ago
parent d48fd158b7
commit a99fde4d3b

@ -62,7 +62,8 @@
failure:(void (^)(NSError *error))failure
{
if(!identifier) {
NSError *error = OWSErrorWithCodeDescription(1, @"Cannot lookup nil identifier");
NSError *error
= OWSErrorWithCodeDescription(OWSErrorCodeInvalidMethodParameters, @"Cannot lookup nil identifier");
BLOCK_SAFE_RUN(failure, error);
return;
}

@ -0,0 +1,21 @@
// Copyright © 2016 Open Whisper Systems. All rights reserved.
#import "TSYapDatabaseObject.h"
#import <Mantle/MTLJSONAdapter.h>
NS_ASSUME_NONNULL_BEGIN
@interface OWSDevice : TSYapDatabaseObject <MTLJSONSerializing>
@property (nonatomic, readonly) NSInteger deviceId;
@property (nullable, nonatomic, readonly) NSString *name;
@property (nonatomic, readonly) NSDate *createdAt;
@property (nonatomic, readonly) NSDate *lastSeenAt;
+ (instancetype)deviceFromJSONDictionary:(NSDictionary *)deviceAttributes error:(NSError **)error;
+ (NSArray<OWSDevice *> *)secondaryDevices;
+ (void)replaceAll:(NSArray<OWSDevice *> *)devices;
@end
NS_ASSUME_NONNULL_END

@ -0,0 +1,120 @@
// Copyright © 2016 Open Whisper Systems. All rights reserved.
#import "OWSDevice.h"
#import "NSDate+millisecondTimeStamp.h"
#import "OWSError.h"
#import "YapDatabaseConnection.h"
#import "YapDatabaseTransaction.h"
#import <Mantle/MTLValueTransformer.h>
NS_ASSUME_NONNULL_BEGIN
static MTLValueTransformer *_millisecondTimestampToDateTransformer;
static int const OWSDevicePrimaryDeviceId = 1;
@implementation OWSDevice
@synthesize name = _name;
+ (instancetype)deviceFromJSONDictionary:(NSDictionary *)deviceAttributes error:(NSError **)error
{
return [MTLJSONAdapter modelOfClass:[self class] fromJSONDictionary:deviceAttributes error:error];
}
+ (NSDictionary *)JSONKeyPathsByPropertyKey
{
return @{
@"createdAt": @"created",
@"lastSeenAt": @"lastSeen",
@"deviceId": @"id",
@"name": @"name"
};
}
+ (MTLValueTransformer *)createdAtJSONTransformer
{
return self.millisecondTimestampToDateTransformer;
}
+ (MTLValueTransformer *)lastSeenAtJSONTransformer
{
return self.millisecondTimestampToDateTransformer;
}
+ (void)replaceAll:(NSArray<OWSDevice *> *)devices
{
[self.dbConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
[transaction removeAllObjectsInCollection:[self collection]];
for (OWSDevice *device in devices) {
[device saveWithTransaction:transaction];
}
}];
}
+ (MTLValueTransformer *)millisecondTimestampToDateTransformer
{
if (!_millisecondTimestampToDateTransformer) {
_millisecondTimestampToDateTransformer =
[MTLValueTransformer transformerUsingForwardBlock:^id(id value, BOOL *success, NSError **error) {
if ([value isKindOfClass:[NSNumber class]]) {
NSNumber *number = (NSNumber *)value;
NSDate *result = [NSDate ows_dateWithMillisecondsSince1970:[number longLongValue]];
if (result) {
*success = YES;
return result;
}
}
*success = NO;
*error = OWSErrorWithCodeDescription(OWSErrorCodeFailedToDecodeJson,
[NSString stringWithFormat:@"unable to decode date from %@", value]);
return nil;
}
reverseBlock:^id(id value, BOOL *success, NSError **error) {
if ([value isKindOfClass:[NSDate class]]) {
NSDate *date = (NSDate *)value;
NSNumber *result = [NSNumber numberWithLongLong:[NSDate ows_millisecondsSince1970ForDate:date]];
if (result) {
*success = YES;
return result;
}
}
*error = OWSErrorWithCodeDescription(OWSErrorCodeFailedToEncodeJson,
[NSString stringWithFormat:@"unable to encode date from %@", value]);
*success = NO;
return nil;
}];
}
return _millisecondTimestampToDateTransformer;
}
+ (NSArray<OWSDevice *> *)secondaryDevices
{
NSMutableArray<OWSDevice *> *devices = [NSMutableArray new];
[self enumerateCollectionObjectsUsingBlock:^(id obj, BOOL *stop) {
if ([obj isKindOfClass:[OWSDevice class]]) {
OWSDevice *device = (OWSDevice *)obj;
if (device.deviceId != OWSDevicePrimaryDeviceId) {
[devices addObject:device];
}
}
}];
return [devices copy];
}
- (nullable NSString *)name
{
if (_name) {
return _name;
}
if (self.deviceId == OWSDevicePrimaryDeviceId) {
return @"This Device";
}
return NSLocalizedString(@"UNNAMED_DEVICE", @"Label text in device manager for a device with no name");
}
@end
NS_ASSUME_NONNULL_END

@ -0,0 +1,18 @@
// Copyright © 2016 Open Whisper Systems. All rights reserved.
NS_ASSUME_NONNULL_BEGIN
@class OWSDevice;
@interface OWSDevicesService : NSObject
- (void)getDevicesWithSuccess:(void (^)(NSArray<OWSDevice *> *))successCallback
failure:(void (^)(NSError *))failureCallback;
- (void)unlinkDevice:(OWSDevice *)device
success:(void (^)())successCallback
failure:(void (^)(NSError *))failureCallback;
@end
NS_ASSUME_NONNULL_END

@ -0,0 +1,84 @@
// Copyright © 2016 Open Whisper Systems. All rights reserved.
#import "OWSDevicesService.h"
#import "OWSDeleteDeviceRequest.h"
#import "OWSDevice.h"
#import "OWSError.h"
#import "OWSGetDevicesRequest.h"
#import "TSNetworkManager.h"
#import <Mantle/MTLJSONAdapter.h>
NS_ASSUME_NONNULL_BEGIN
@implementation OWSDevicesService
- (void)getDevicesWithSuccess:(void (^)(NSArray<OWSDevice *> *))successCallback
failure:(void (^)(NSError *))failureCallback
{
OWSGetDevicesRequest *request = [OWSGetDevicesRequest new];
[[TSNetworkManager sharedManager] makeRequest:request
success:^(NSURLSessionDataTask *task, id responseObject) {
DDLogVerbose(@"Get devices request succeeded");
NSArray<OWSDevice *> *devices = [self parseResponse:responseObject];
if (devices) {
successCallback(devices);
} else {
failureCallback(OWSErrorWithCodeDescription(
OWSErrorCodeUnableToProcessServerResponse, @"Unable to parse server response"));
}
}
failure:^(NSURLSessionDataTask *task, NSError *error) {
DDLogVerbose(@"Get devices request failed with error: %@", error);
failureCallback(error);
}];
}
- (void)unlinkDevice:(OWSDevice *)device
success:(void (^)())successCallback
failure:(void (^)(NSError *))failureCallback
{
OWSDeleteDeviceRequest *request = [[OWSDeleteDeviceRequest alloc] initWithDevice:device];
[[TSNetworkManager sharedManager] makeRequest:request
success:^(NSURLSessionDataTask *task, id responseObject) {
DDLogVerbose(@"Delete device request succeeded");
successCallback();
}
failure:^(NSURLSessionDataTask *task, NSError *error) {
DDLogVerbose(@"Get devices request failed with error: %@", error);
failureCallback(error);
}];
}
- (NSArray<OWSDevice *> *)parseResponse:(id)responseObject
{
if (![responseObject isKindOfClass:[NSDictionary class]]) {
DDLogError(@"Device response was not a dictionary.");
return nil;
}
NSDictionary *response = (NSDictionary *)responseObject;
NSArray<NSDictionary *> *devicesAttributes = response[@"devices"];
if (!devicesAttributes) {
DDLogError(@"Device response had no devices.");
return nil;
}
NSMutableArray<OWSDevice *> *devices = [NSMutableArray new];
for (NSDictionary *deviceAttributes in devicesAttributes) {
NSError *error;
OWSDevice *device = [OWSDevice deviceFromJSONDictionary:deviceAttributes error:&error];
if (error) {
DDLogError(@"Failed to build device from dictionary with error: %@", error);
} else {
[devices addObject:device];
}
}
return [devices copy];
}
@end
NS_ASSUME_NONNULL_END

@ -0,0 +1,15 @@
// Copyright © 2016 Open Whisper Systems. All rights reserved.
#import "TSRequest.h"
NS_ASSUME_NONNULL_BEGIN
@class OWSDevice;
@interface OWSDeleteDeviceRequest : TSRequest
- (instancetype)initWithDevice:(OWSDevice *)device;
@end
NS_ASSUME_NONNULL_END

@ -0,0 +1,27 @@
// Copyright © 2016 Open Whisper Systems. All rights reserved.
#import "OWSDeleteDeviceRequest.h"
#import "OWSDevice.h"
#import "TSConstants.h"
NS_ASSUME_NONNULL_BEGIN
@implementation OWSDeleteDeviceRequest
- (instancetype)initWithDevice:(OWSDevice *)device
{
NSString *deleteDevicePath = [NSString
stringWithFormat:textSecureDevicesAPIFormat, [NSString stringWithFormat:@"%ld", (long)device.deviceId]];
self = [super initWithURL:[NSURL URLWithString:deleteDevicePath]];
if (!self) {
return self;
}
[self setHTTPMethod:@"DELETE"];
return self;
}
@end
NS_ASSUME_NONNULL_END

@ -0,0 +1,11 @@
// Copyright © 2016 Open Whisper Systems. All rights reserved.
#import "TSRequest.h"
NS_ASSUME_NONNULL_BEGIN
@interface OWSGetDevicesRequest : TSRequest
@end
NS_ASSUME_NONNULL_END

@ -0,0 +1,25 @@
// Copyright © 2016 Open Whisper Systems. All rights reserved.
#import "OWSGetDevicesRequest.h"
#import "TSConstants.h"
NS_ASSUME_NONNULL_BEGIN
@implementation OWSGetDevicesRequest
- (instancetype)init
{
NSString *getDevicesPath = [NSString stringWithFormat:textSecureDevicesAPIFormat, @""];
self = [super initWithURL:[NSURL URLWithString:getDevicesPath]];
if (!self) {
return self;
}
[self setHTTPMethod:@"GET"];
return self;
}
@end
NS_ASSUME_NONNULL_END

@ -38,6 +38,7 @@ typedef enum { kSMSVerification, kPhoneNumberVerification } VerificationTranspor
#define textSecureAttachmentsAPI @"v1/attachments"
#define textSecureDeviceProvisioningCodeAPI @"v1/devices/provisioning/code"
#define textSecureDeviceProvisioningAPIFormat @"v1/provisioning/%@"
#define textSecureDevicesAPIFormat @"v1/devices/%@"
typedef void (^successCompletionBlock)(void);
typedef void (^failedRegistrationRequestBlock)(void);

@ -1,13 +1,11 @@
//
// NSDate+millisecondTimeStamp.h
// Signal
//
// Created by Frederic Jacobs on 25/11/14.
// Copyright (c) 2014 Open Whisper Systems. All rights reserved.
//
#import <Foundation/Foundation.h>
@interface NSDate (millisecondTimeStamp)
+ (uint64_t)ows_millisecondTimeStamp;
+ (NSDate *)ows_dateWithMillisecondsSince1970:(uint64_t)milliseconds;
+ (uint64_t)ows_millisecondsSince1970ForDate:(NSDate *)date;
@end

@ -1,10 +1,5 @@
//
// NSDate+millisecondTimeStamp.m
// Signal
//
// Created by Frederic Jacobs on 25/11/14.
// Copyright (c) 2014 Open Whisper Systems. All rights reserved.
//
#import <chrono>
#import "NSDate+millisecondTimeStamp.h"
@ -17,4 +12,14 @@
return milliseconds;
}
+ (NSDate *)ows_dateWithMillisecondsSince1970:(uint64_t)milliseconds
{
return [NSDate dateWithTimeIntervalSince1970:(milliseconds / 1000.0)];
}
+ (uint64_t)ows_millisecondsSince1970ForDate:(NSDate *)date
{
return (uint64_t)(date.timeIntervalSince1970 * 1000);
}
@end

@ -4,6 +4,13 @@ NS_ASSUME_NONNULL_BEGIN
extern NSString *const OWSSignalServiceKitErrorDomain;
extern NSError *OWSErrorWithCodeDescription(NSInteger code, NSString *description);
typedef NS_ENUM(NSInteger, OWSErrorCode) {
OWSErrorCodeInvalidMethodParameters = 11,
OWSErrorCodeUnableToProcessServerResponse = 12,
OWSErrorCodeFailedToDecodeJson = 13,
OWSErrorCodeFailedToEncodeJson = 14
};
extern NSError *OWSErrorWithCodeDescription(OWSErrorCode code, NSString *description);
NS_ASSUME_NONNULL_END

@ -6,7 +6,7 @@ NS_ASSUME_NONNULL_BEGIN
NSString *const OWSSignalServiceKitErrorDomain = @"OWSSignalServiceKitErrorDomain";
NSError *OWSErrorWithCodeDescription(NSInteger code, NSString *description)
NSError *OWSErrorWithCodeDescription(OWSErrorCode code, NSString *description)
{
return [NSError errorWithDomain:OWSSignalServiceKitErrorDomain
code:code

Loading…
Cancel
Save