From 7d5175ea4d04cf6b333249f295caca9d811b6865 Mon Sep 17 00:00:00 2001 From: Przemek Zygmunt Date: Sun, 27 Oct 2019 19:20:30 +0100 Subject: [PATCH 01/11] Unnesesary log --- SUPLA/SAChannelBase+CoreDataClass.m | 3 --- 1 file changed, 3 deletions(-) diff --git a/SUPLA/SAChannelBase+CoreDataClass.m b/SUPLA/SAChannelBase+CoreDataClass.m index e13593d5..953f9fa0 100644 --- a/SUPLA/SAChannelBase+CoreDataClass.m +++ b/SUPLA/SAChannelBase+CoreDataClass.m @@ -349,9 +349,6 @@ - (UIImage*) getIconWithIndex:(short)idx { UIImage *img = nil; @try { - if (self.remote_id == 127) { - NSLog(@"%@", self.usericon); - } if (data != nil && [data isKindOfClass:[NSData class]]) { img = [UIImage imageWithData:(NSData*)data]; } From b12008a917a271d49104f90e94e150ee406b97c2 Mon Sep 17 00:00:00 2001 From: Przemek Zygmunt Date: Sun, 27 Oct 2019 19:22:36 +0100 Subject: [PATCH 02/11] Disable logs --- SUPLA/ChartDetailView.m | 4 ++-- SUPLA/Database.m | 1 - SUPLA/MainVC.m | 4 ++-- 3 files changed, 4 insertions(+), 5 deletions(-) diff --git a/SUPLA/ChartDetailView.m b/SUPLA/ChartDetailView.m index d39d25c5..e405d327 100644 --- a/SUPLA/ChartDetailView.m +++ b/SUPLA/ChartDetailView.m @@ -103,12 +103,12 @@ -(void) runDownloadTask { } -(void) onRestApiTaskStarted: (SARestApiClientTask*)task { - NSLog(@"onRestApiTaskStarted"); + // NSLog(@"onRestApiTaskStarted"); [self.lPreloader animateWithTimeInterval:0.1]; } -(void) onRestApiTaskFinished: (SARestApiClientTask*)task { - NSLog(@"onRestApiTaskFinished"); + // NSLog(@"onRestApiTaskFinished"); if (_task != nil && task == _task) { _task.delegate = nil; _task = nil; diff --git a/SUPLA/Database.m b/SUPLA/Database.m index 1685f403..7ca71d6a 100644 --- a/SUPLA/Database.m +++ b/SUPLA/Database.m @@ -1334,7 +1334,6 @@ -(void) deleteAllUserIcons { del = YES; for(int a=0;a Date: Tue, 29 Oct 2019 19:01:46 +0100 Subject: [PATCH 03/11] XIB group --- SUPLA.xcodeproj/project.pbxproj | 54 +++++++++++++++++++-------------- 1 file changed, 31 insertions(+), 23 deletions(-) diff --git a/SUPLA.xcodeproj/project.pbxproj b/SUPLA.xcodeproj/project.pbxproj index f2f86c6d..57f8b9e3 100644 --- a/SUPLA.xcodeproj/project.pbxproj +++ b/SUPLA.xcodeproj/project.pbxproj @@ -995,6 +995,36 @@ /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ + 012119122368B597004C1993 /* xib */ = { + isa = PBXGroup; + children = ( + 01C8EBCF23422AC50072AB8C /* HomePlusDetailViewGroupCell.xib */, + 40CE7C6D1DCBBF6D00BBACE4 /* DistanceCell.xib */, + 017A3C8823633A70004AD1FC /* TempHumidityDetailView.xib */, + 01902A29235A1840005ED935 /* TemperatureDetailView.xib */, + 407D4AFE1BC6E491009A5505 /* StatusVC.xib */, + 40BE3E611BCA7AEF00153680 /* ChannelCell.xib */, + 406778541BCBF9F4008DD37F /* SectionCell.xib */, + 40DE1A3A1BCD5E9B004CF43B /* AboutVC.xib */, + 4038A5531CE32B6800180B5D /* TempHumidityCell.xib */, + 40DB208F1DC9049400FAFAB0 /* RGBDetail.xib */, + 019F4CAE2354DC3300286139 /* ImpulseCounterDetailView.xib */, + 01D0617322C296850043C947 /* ElectricityMeterDetailView.xib */, + 01C8EBFC234232EC0072AB8C /* HomePlusDetailView.xib */, + 40CE7C631DCBBCE400BBACE4 /* MeasurementCell.xib */, + 40F951471FD0654900698587 /* RSDetail.xib */, + 407D31961FD1A7070062FB80 /* AddWizardVC.xib */, + 4077ACE220A21BB100BD2216 /* CreateAccountVC.xib */, + 01F9111022EF989100BFF91D /* HomePlusCell.xib */, + 40844D811FB0DDB000432AA0 /* SettingsVC.xib */, + 401CA1EE1BA0923600117AF4 /* MainVC.xib */, + 408034E41BC84A89007666E7 /* NavigationController.xib */, + 01D4293922AAAA450050C1A2 /* IncrementalMeterCell.xib */, + 406778281BCBBC83008DD37F /* ThermometerCell.xib */, + ); + name = xib; + sourceTree = ""; + }; 013D1C5A22CE4751000C0784 /* charts */ = { isa = PBXGroup; children = ( @@ -1497,7 +1527,7 @@ 40A675851BA1BEBF004A51C4 /* UI */ = { isa = PBXGroup; children = ( - 40844D811FB0DDB000432AA0 /* SettingsVC.xib */, + 012119122368B597004C1993 /* xib */, 40C9E4FB1F2B841400753796 /* SAColorListPicker.h */, 40C9E4FC1F2B841400753796 /* SAColorListPicker.m */, 40C9E4F51F2A186A00753796 /* SARollerShutter.h */, @@ -1507,33 +1537,23 @@ 4031ACFA1BBC0FFB00CF9D8B /* MGSwipe */, 40A675801BA1BE8E004A51C4 /* SettingsVC.h */, 40A675811BA1BE8E004A51C4 /* SettingsVC.m */, - 401CA1EE1BA0923600117AF4 /* MainVC.xib */, 401CA1C61BA067DB00117AF4 /* MainVC.h */, 401CA1C71BA067DB00117AF4 /* MainVC.m */, 4017E1291BB9CE2900570AC8 /* ChannelCell.h */, 4017E12A1BB9CE2900570AC8 /* ChannelCell.m */, 407D4AFC1BC6E491009A5505 /* StatusVC.h */, 407D4AFD1BC6E491009A5505 /* StatusVC.m */, - 407D4AFE1BC6E491009A5505 /* StatusVC.xib */, 40CF96DC1BC820E60030EFFF /* UIHelper.h */, 40CF96DD1BC820E60030EFFF /* UIHelper.m */, 408034E21BC84A89007666E7 /* NavigationController.h */, 408034E31BC84A89007666E7 /* NavigationController.m */, - 408034E41BC84A89007666E7 /* NavigationController.xib */, - 40BE3E611BCA7AEF00153680 /* ChannelCell.xib */, - 01D4293922AAAA450050C1A2 /* IncrementalMeterCell.xib */, - 406778281BCBBC83008DD37F /* ThermometerCell.xib */, 406778521BCBF9F4008DD37F /* SectionCell.h */, 406778531BCBF9F4008DD37F /* SectionCell.m */, - 406778541BCBF9F4008DD37F /* SectionCell.xib */, 40DE1A331BCD1B55004CF43B /* AboutVC.h */, 40DE1A341BCD1B55004CF43B /* AboutVC.m */, - 40DE1A3A1BCD5E9B004CF43B /* AboutVC.xib */, 40B397CE1BCE7F3200BE7D5A /* Launch Screen.storyboard */, - 4038A5531CE32B6800180B5D /* TempHumidityCell.xib */, 4006E9081DC62D0A00C4456D /* DetailView.h */, 4006E9091DC62D0A00C4456D /* DetailView.m */, - 40DB208F1DC9049400FAFAB0 /* RGBDetail.xib */, 403150F91DC769430075D2D2 /* RGBDetailView.h */, 01D0616C22C294D90043C947 /* ElectricityMeterDetailView.h */, 012023C0234E54ED00E131B7 /* ImpulseCounterDetailView.h */, @@ -1541,30 +1561,19 @@ 01392B38235CA8B1003A2BAD /* ChartDetailView.h */, 01392B39235CA8B1003A2BAD /* ChartDetailView.m */, 01902A23235A17E9005ED935 /* TemperatureDetailView.h */, - 017A3C8823633A70004AD1FC /* TempHumidityDetailView.xib */, - 01902A29235A1840005ED935 /* TemperatureDetailView.xib */, 01902A24235A17E9005ED935 /* TemperatureDetailView.m */, 01902A26235A180F005ED935 /* TempHumidityDetailView.h */, 01902A27235A180F005ED935 /* TempHumidityDetailView.m */, - 019F4CAE2354DC3300286139 /* ImpulseCounterDetailView.xib */, 01D0616D22C294D90043C947 /* ElectricityMeterDetailView.m */, - 01D0617322C296850043C947 /* ElectricityMeterDetailView.xib */, - 01C8EBFC234232EC0072AB8C /* HomePlusDetailView.xib */, 403150FA1DC769430075D2D2 /* RGBDetailView.m */, - 40CE7C631DCBBCE400BBACE4 /* MeasurementCell.xib */, - 40CE7C6D1DCBBF6D00BBACE4 /* DistanceCell.xib */, 409934B41F30EF9C003110C5 /* RSDetailView.h */, 409934B51F30EF9C003110C5 /* RSDetailView.m */, - 40F951471FD0654900698587 /* RSDetail.xib */, 403EB1111FBDF47F00AD6460 /* AddWizardVC.h */, 403EB1121FBDF47F00AD6460 /* AddWizardVC.m */, - 407D31961FD1A7070062FB80 /* AddWizardVC.xib */, 4077ACE020A21BB100BD2216 /* CreateAccountVC.h */, 4077ACE120A21BB100BD2216 /* CreateAccountVC.m */, - 4077ACE220A21BB100BD2216 /* CreateAccountVC.xib */, 40B610CA20C7E263002B762A /* SAUIChannelStatus.h */, 40B610CB20C7E263002B762A /* SAUIChannelStatus.m */, - 01F9111022EF989100BFF91D /* HomePlusCell.xib */, 017554F422F1A62500EB58B7 /* HomePlusDetailView.h */, 017554F522F1A62500EB58B7 /* HomePlusDetailView.m */, 0122613722F396440013E6A2 /* SAThermostatCalendar.h */, @@ -1573,7 +1582,6 @@ 0122613822F396440013E6A2 /* SAThermostatCalendar.m */, 019D22EE233CC2D000F17135 /* SAPreloader.h */, 019D22EF233CC2D000F17135 /* SAPreloader.m */, - 01C8EBCF23422AC50072AB8C /* HomePlusDetailViewGroupCell.xib */, ); name = UI; sourceTree = ""; From ac474c6d3211e5f3ad7624e05caf6cdfda2dd762 Mon Sep 17 00:00:00 2001 From: Przemek Zygmunt Date: Tue, 29 Oct 2019 20:11:57 +0100 Subject: [PATCH 04/11] Location collapse --- SUPLA.xcodeproj/project.pbxproj | 8 +- SUPLA/Database.h | 1 + SUPLA/Database.m | 6 +- SUPLA/MainVC.h | 5 +- SUPLA/MainVC.m | 84 +++++++++- SUPLA/NavigationController.m | 6 +- SUPLA/Resources/Assets/Img/collapsed@3x.png | Bin 0 -> 1180 bytes SUPLA/SUPLA.xcdatamodeld/.xccurrentversion | 2 +- .../SUPLA 5.xcdatamodel/contents | 146 ++++++++++++++++++ SUPLA/SectionCell.h | 9 +- SUPLA/SectionCell.m | 33 +++- SUPLA/SectionCell.xib | 31 +++- SUPLA/_SALocation+CoreDataProperties.h | 33 ++-- SUPLA/_SALocation+CoreDataProperties.m | 35 +++-- 14 files changed, 336 insertions(+), 63 deletions(-) create mode 100644 SUPLA/Resources/Assets/Img/collapsed@3x.png create mode 100644 SUPLA/SUPLA.xcdatamodeld/SUPLA 5.xcdatamodel/contents diff --git a/SUPLA.xcodeproj/project.pbxproj b/SUPLA.xcodeproj/project.pbxproj index 57f8b9e3..0a8ee361 100644 --- a/SUPLA.xcodeproj/project.pbxproj +++ b/SUPLA.xcodeproj/project.pbxproj @@ -8,6 +8,7 @@ /* Begin PBXBuildFile section */ 012023C2234E54ED00E131B7 /* ImpulseCounterDetailView.m in Sources */ = {isa = PBXBuildFile; fileRef = 012023C1234E54ED00E131B7 /* ImpulseCounterDetailView.m */; }; + 012119152368C3B2004C1993 /* collapsed@3x.png in Resources */ = {isa = PBXBuildFile; fileRef = 012119142368C3B2004C1993 /* collapsed@3x.png */; }; 0122613922F396440013E6A2 /* SAThermostatCalendar.m in Sources */ = {isa = PBXBuildFile; fileRef = 0122613822F396440013E6A2 /* SAThermostatCalendar.m */; }; 012F722C22DF3E2300E5F72E /* ChartFilterFieldTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 012F722822DF3CF000E5F72E /* ChartFilterFieldTests.m */; }; 012F722E22DFA0BE00E5F72E /* SABarChartDataSet.swift in Sources */ = {isa = PBXBuildFile; fileRef = 012F722D22DFA0BE00E5F72E /* SABarChartDataSet.swift */; }; @@ -363,6 +364,8 @@ /* Begin PBXFileReference section */ 012023C0234E54ED00E131B7 /* ImpulseCounterDetailView.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ImpulseCounterDetailView.h; sourceTree = ""; }; 012023C1234E54ED00E131B7 /* ImpulseCounterDetailView.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ImpulseCounterDetailView.m; sourceTree = ""; }; + 012119132368BDB0004C1993 /* SUPLA 5.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = "SUPLA 5.xcdatamodel"; sourceTree = ""; }; + 012119142368C3B2004C1993 /* collapsed@3x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "collapsed@3x.png"; path = "Resources/Assets/Img/collapsed@3x.png"; sourceTree = ""; }; 0122613722F396440013E6A2 /* SAThermostatCalendar.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SAThermostatCalendar.h; sourceTree = ""; }; 0122613822F396440013E6A2 /* SAThermostatCalendar.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SAThermostatCalendar.m; sourceTree = ""; }; 012F722822DF3CF000E5F72E /* ChartFilterFieldTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ChartFilterFieldTests.m; sourceTree = ""; }; @@ -1214,6 +1217,7 @@ 405AC4011BC15878004F7311 /* Img */ = { isa = PBXGroup; children = ( + 012119142368C3B2004C1993 /* collapsed@3x.png */, 017A3CA523635C22004AD1FC /* weight@2x.png */, 017A3CA623635C22004AD1FC /* weight@3x.png */, 017A3CAD23635DF7004AD1FC /* pressure@2x.png */, @@ -1715,6 +1719,7 @@ 4052DA0D1DC515AE000B8C45 /* rgb-off@2x.png in Resources */, 40CE7C6B1DCBBD5700BBACE4 /* depth@2x.png in Resources */, 40DE1A2D1BCCFF8A004CF43B /* settings@2x.png in Resources */, + 012119152368C3B2004C1993 /* collapsed@3x.png in Resources */, 405AC4341BC15C08004F7311 /* logo-supla@2x.png in Resources */, 405C49A11FCAFFD400C15602 /* wizard_ok@2x.png in Resources */, 017A3C8623633A70004AD1FC /* TempHumidityDetailView.xib in Resources */, @@ -2623,12 +2628,13 @@ 407004251BB5706500F6187F /* SUPLA.xcdatamodeld */ = { isa = XCVersionGroup; children = ( + 012119132368BDB0004C1993 /* SUPLA 5.xcdatamodel */, 01CFF6D12365BCCD00C827FB /* SUPLA 4.xcdatamodel */, 01B216CF22AECB2F004E0596 /* SUPLA 3.xcdatamodel */, 40BBA34620AC52EA0054CD20 /* SUPLA 2.xcdatamodel */, 407004261BB5706500F6187F /* SUPLA.xcdatamodel */, ); - currentVersion = 01CFF6D12365BCCD00C827FB /* SUPLA 4.xcdatamodel */; + currentVersion = 012119132368BDB0004C1993 /* SUPLA 5.xcdatamodel */; path = SUPLA.xcdatamodeld; sourceTree = ""; versionGroupType = wrapper.xcdatamodel; diff --git a/SUPLA/Database.h b/SUPLA/Database.h index 10ffcb45..e925394a 100644 --- a/SUPLA/Database.h +++ b/SUPLA/Database.h @@ -61,6 +61,7 @@ typedef NS_ENUM(NSUInteger, GroupBy) { - (void)saveContext; -(_SALocation*) fetchLocationById:(int)location_id; +-(NSArray*) fetchVisibleLocations; -(_SALocation*) newLocation; -(BOOL) updateLocation:(TSC_SuplaLocation *)location; diff --git a/SUPLA/Database.m b/SUPLA/Database.m index 7ca71d6a..b10fd9e4 100644 --- a/SUPLA/Database.m +++ b/SUPLA/Database.m @@ -62,7 +62,7 @@ - (NSPersistentStoreCoordinator *)persistentStoreCoordinator { return _persistentStoreCoordinator; } - int DBv = 7; + int DBv = 8; [self removeIfExists:@"SUPLA_DB.sqlite"]; @@ -250,6 +250,10 @@ -(_SALocation*) fetchLocationById:(int)location_id { return [self fetchItemByPredicate:[NSPredicate predicateWithFormat:@"location_id = %i", location_id] entityName:@"SALocation"]; }; +-(NSArray*) fetchVisibleLocations { + return [self fetchByPredicate:[NSPredicate predicateWithFormat:@"visible > 0"] entityName:@"SALocation" limit:0 sortDescriptors:nil]; +} + -(_SALocation*) newLocation { _SALocation *Location = [[_SALocation alloc] initWithEntity:[NSEntityDescription entityForName:@"SALocation" inManagedObjectContext:self.managedObjectContext] insertIntoManagedObjectContext:self.managedObjectContext]; diff --git a/SUPLA/MainVC.h b/SUPLA/MainVC.h index 908e33a8..c998162a 100644 --- a/SUPLA/MainVC.h +++ b/SUPLA/MainVC.h @@ -18,10 +18,11 @@ #import #import "SADownloadUserIcons.h" +#import "SectionCell.h" @class SADetailView; -@interface SAMainVC : UIViewController +@interface SAMainVC : UIViewController - (IBAction)settingsTouched:(id)sender; @@ -34,7 +35,7 @@ @property (weak, nonatomic) IBOutlet UILabel *notificationLabel; - (void)detailHide; - +- (void)groupTableHidden:(BOOL)hidden; @end diff --git a/SUPLA/MainVC.m b/SUPLA/MainVC.m index 23c53cd0..94764811 100644 --- a/SUPLA/MainVC.m +++ b/SUPLA/MainVC.m @@ -22,7 +22,6 @@ #import "SuplaApp.h" #import "Database.h" #import "SAChannel+CoreDataClass.h" -#import "SectionCell.h" #import "RGBDetailView.h" #import "RSDetailView.h" #import "ElectricityMeterDetailView.h" @@ -31,6 +30,7 @@ #import "TemperatureDetailView.h" #import "TempHumidityDetailView.h" #import "SARateApp.h" +#import "_SALocation+CoreDataClass.h" @implementation SAMainVC { NSFetchedResultsController *_cFrc; @@ -46,7 +46,7 @@ @implementation SAMainVC { NSTimer *_nTimer; UITapGestureRecognizer *_tapRecognizer; SADownloadUserIcons *_task; - + NSArray *_locations; } - (void)registerNibForTableView:(UITableView*)tv { @@ -104,6 +104,8 @@ - (void)didReceiveMemoryWarning { -(void)onDataChanged { _cFrc = nil; _gFrc = nil; + _locations = nil; + [self.cTableView reloadData]; [self.gTableView reloadData]; } @@ -231,6 +233,27 @@ - (void)detailHide { [(SAMainView*)self.view detailShow:NO animated:NO]; } +#pragma mark Locations + +- (_SALocation *) locationByName:(NSString *)name { + if (name == nil) { + return nil; + } + + if (_locations == nil) { + _locations = [SAApp.DB fetchVisibleLocations]; + if (_locations == nil) { + _locations = [[NSArray alloc] init]; + } + } + + NSUInteger idx = [_locations indexOfObjectPassingTest:^BOOL(id obj, NSUInteger idx, BOOL *stop) { + return [((_SALocation*)obj).caption isEqualToString:name]; + }]; + + return idx == NSNotFound ? nil : (_SALocation*)[_locations objectAtIndex:idx]; +} + #pragma mark Table Support - (NSFetchedResultsController*)frcForTableView:(UITableView*)tableView { @@ -261,16 +284,42 @@ - (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInte return [[[[self frcForTableView:tableView] sections] objectAtIndex:section] name]; } +- (short)bitFlagCollapse { + return self.cTableView.hidden == NO ? 0x1 : 0x2; +} + - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { + NSFetchedResultsController *frc = [self frcForTableView:tableView]; if ( frc ) { id sectionInfo = [[frc sections] objectAtIndex:section]; + _SALocation *location = [self locationByName:sectionInfo.name]; + if (location != nil + && (location.collapsed & [self bitFlagCollapse]) > 0) { + return 0; + } return [sectionInfo numberOfObjects]; } return 0; } +- (void)sectionCellTouch:(SASectionCell*)section { + + _SALocation *location = [self locationByName:section.label.text]; + if (location) { + short bit = [self bitFlagCollapse]; + if ((location.collapsed & bit) > 0) { + location.collapsed ^= bit; + } else { + location.collapsed |= bit; + } + + [SAApp.DB saveContext]; + [self onDataChanged]; + } +} + - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { SAChannelBase *channel_base = [[self frcForTableView:tableView] objectAtIndexPath:indexPath]; @@ -320,9 +369,12 @@ -(UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger) { SASectionCell *cell = [tableView dequeueReusableCellWithIdentifier:@"SectionCell"]; if ( cell ) { - [cell.label setText:[[[[self frcForTableView:tableView] sections] objectAtIndex:section] name]]; + NSString *name = [[[[self frcForTableView:tableView] sections] objectAtIndex:section] name]; + _SALocation *location = [self locationByName:name]; + cell.ivCollapsed.hidden = location == nil || (location.collapsed & [self bitFlagCollapse]) == 0; + [cell.label setText:name]; + cell.delegate = self; } - return cell; } @@ -331,6 +383,13 @@ - (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSIntege return 50; } +- (void)groupTableHidden:(BOOL)hidden { + self.cTableView.hidden = !hidden; + self.gTableView.hidden = hidden; + + [self onDataChanged]; +} + - (IBAction)settingsTouched:(id)sender { [[SAApp UI ] showSettings]; @@ -409,7 +468,6 @@ -(void)initMainView { _animating = NO; _panRecognizer = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(handlePan:)]; [self addGestureRecognizer:_panRecognizer]; - } -(SADetailView*)detailView { @@ -638,12 +696,9 @@ - (void)detailShow:(BOOL)show animated:(BOOL)animated { } } - - } - - (void)handlePan:(UIPanGestureRecognizer *)gr { if ( _animating ) @@ -724,5 +779,18 @@ -(void)moveCenter:(float)x_offset { [self setCenter:CGPointMake(self.center.x+x_offset, self.center.y)]; } +- (void)handleTap:(UITapGestureRecognizer *)gr { + if ( _animating ) + return; + + UITableView *tableView = self.cTableView.hidden ? self.gTableView : self.cTableView; + CGPoint touch_point = [gr locationInView:tableView]; + NSIndexPath *path = [tableView indexPathForRowAtPoint:touch_point]; + + SASectionCell *section = [tableView cellForRowAtIndexPath:path]; + if ([section isKindOfClass:[SASectionCell class]]) { + + } +} @end diff --git a/SUPLA/NavigationController.m b/SUPLA/NavigationController.m index 8f35e534..80bad274 100644 --- a/SUPLA/NavigationController.m +++ b/SUPLA/NavigationController.m @@ -212,13 +212,11 @@ - (IBAction)groupsTouch:(id)sender { if ( self.btnGroups.tag == 1 ) { [self.btnGroups setImage:[UIImage imageNamed:@"groupsoff.png"]]; self.btnGroups.tag = 0; - MainVC.cTableView.hidden = NO; - MainVC.gTableView.hidden = YES; + [MainVC groupTableHidden: YES]; } else { [self.btnGroups setImage:[UIImage imageNamed:@"groupson.png"]]; self.btnGroups.tag = 1; - MainVC.cTableView.hidden = YES; - MainVC.gTableView.hidden = NO; + [MainVC groupTableHidden: NO]; } } diff --git a/SUPLA/Resources/Assets/Img/collapsed@3x.png b/SUPLA/Resources/Assets/Img/collapsed@3x.png new file mode 100644 index 0000000000000000000000000000000000000000..89d3f8e5b73e4e5488b0783afcb1965432cf6802 GIT binary patch literal 1180 zcmeAS@N?(olHy`uVBq!ia0vp^zkqlS2OE$KbKF)1q}Y^7$z`G_|-Yj0w}^+ z;1O92)Nvhz8J#p{R{#asOFVsD*&nm;b8~3Vy#8`C0|Seur;B4q#jUq@Z?6>&6k)zF zLra6L^VUR-HoXVjoQiVaC#IymdCGTgo49$+*|%j5`)Ypw`m1I%WAV26%JRQ{K3={e zPHdum^>52p3pbqp75^zc&)(fmq%89P&VOs(K7Y}ENbmK3_4;Gqiraw9)hFg}{X6F= zP^H$V^c?&2DvdXry8c|eeg38#*X}h+^-sPP9|J3s2P*ptR^|>=RtHvg52#EYq-_85 zZ^f-(W$(BCje(d}ons#kF>UYd^H(9Jo&Q#R6s+w2uD>x5)3yVZK}_2UR0cM!{_MBQ z9|CTqivIN8K7Sfmef*}sCbmF7xc=M!cKKVdGwO5gd-+>q!zTXE{he70c8~vU|If~e z(?g%^&$oXIk=ylGr}l$DS)}tnV|fwn3C-&gHa0e;e0^AV%z59IuWRHFd{KAxJ7akm1dQ@A*1i4M4G6SH%s^_x7*UU<0WW zVLixK`M+(E21u`;2%Ghjzq30ZfvnOFQ~+sG>1qLKa#;w{)Tto`(j>roIFI?SbjPB^ z>$UaY11;WIy?<}h)gF8OZ|re~gzJU%#|>GWFXYy5H{@u(kXgUnkmvA))cWa$0?Zc^ z>)Q=QoG-@Kmm5knUyQ6zHmQv>v?hB+>-F5_ONw~`c((*d&^@;Qa(i^08mFG9*oygnVRl~Q-ara53Po6K@ z-imeK-#h#7s^yKl8DDI;&M#YZAyNEFVdQ&MBb@0Hc#J9smFU literal 0 HcmV?d00001 diff --git a/SUPLA/SUPLA.xcdatamodeld/.xccurrentversion b/SUPLA/SUPLA.xcdatamodeld/.xccurrentversion index 2c8560c4..5f761ffa 100644 --- a/SUPLA/SUPLA.xcdatamodeld/.xccurrentversion +++ b/SUPLA/SUPLA.xcdatamodeld/.xccurrentversion @@ -3,6 +3,6 @@ _XCCurrentVersionName - SUPLA 4.xcdatamodel + SUPLA 5.xcdatamodel diff --git a/SUPLA/SUPLA.xcdatamodeld/SUPLA 5.xcdatamodel/contents b/SUPLA/SUPLA.xcdatamodeld/SUPLA 5.xcdatamodel/contents new file mode 100644 index 00000000..0b9e6673 --- /dev/null +++ b/SUPLA/SUPLA.xcdatamodeld/SUPLA 5.xcdatamodel/contents @@ -0,0 +1,146 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/SUPLA/SectionCell.h b/SUPLA/SectionCell.h index 28fa1402..e2acb9ad 100644 --- a/SUPLA/SectionCell.h +++ b/SUPLA/SectionCell.h @@ -18,7 +18,14 @@ #import +@class SASectionCell; +@protocol SASectionCellDelegate +@optional +- (void)sectionCellTouch:(SASectionCell*)section; +@end + @interface SASectionCell : UITableViewCell +@property (weak, nonatomic) IBOutlet UIImageView *ivCollapsed; @property (weak, nonatomic) IBOutlet UILabel *label; - +@property (nonatomic, weak, nullable) id delegate; @end diff --git a/SUPLA/SectionCell.m b/SUPLA/SectionCell.m index 914a6d2b..4adc43ef 100644 --- a/SUPLA/SectionCell.m +++ b/SUPLA/SectionCell.m @@ -18,13 +18,38 @@ #import "SectionCell.h" -@implementation SASectionCell +@implementation SASectionCell { + UITapGestureRecognizer *_tap; +} +- (void)initialize { + if (_tap == nil) { + _tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(tapped:)]; + _tap.delegate = self; + [self addGestureRecognizer:_tap]; + } +} -- (void)setSelected:(BOOL)selected animated:(BOOL)animated { - [super setSelected:selected animated:animated]; +- (id)initWithCoder:(NSCoder *)coder +{ + self = [super initWithCoder:coder]; + if (self) { + [self initialize]; + } + return self; +} - // Configure the view for the selected state +- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(nullable NSString *)reuseIdentifier { + self = [super initWithStyle:style reuseIdentifier:reuseIdentifier]; + if (self) { + [self initialize]; + } + return self; } +- (void)tapped:(UITapGestureRecognizer *)gr { + if (self.delegate) { + [self.delegate sectionCellTouch:self]; + } +} @end diff --git a/SUPLA/SectionCell.xib b/SUPLA/SectionCell.xib index eedbbf7a..0961f9a2 100644 --- a/SUPLA/SectionCell.xib +++ b/SUPLA/SectionCell.xib @@ -1,13 +1,13 @@ - - + + + - - + - + Quicksand-Regular @@ -18,35 +18,50 @@ - + + + - + + + + - + + + + diff --git a/SUPLA/_SALocation+CoreDataProperties.h b/SUPLA/_SALocation+CoreDataProperties.h index 067b9965..d0274d7a 100644 --- a/SUPLA/_SALocation+CoreDataProperties.h +++ b/SUPLA/_SALocation+CoreDataProperties.h @@ -1,20 +1,20 @@ /* - Copyright (C) AC SOFTWARE SP. Z O.O. - - This program is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License - as published by the Free Software Foundation; either version 2 - of the License, or (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ +Copyright (C) AC SOFTWARE SP. Z O.O. + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ #import "_SALocation+CoreDataClass.h" @@ -28,6 +28,7 @@ NS_ASSUME_NONNULL_BEGIN @property (nullable, nonatomic, copy) NSString *caption; @property (nullable, nonatomic, copy) NSNumber *location_id; @property (nullable, nonatomic, copy) NSNumber *visible; +@property (nonatomic) int16_t collapsed; @end diff --git a/SUPLA/_SALocation+CoreDataProperties.m b/SUPLA/_SALocation+CoreDataProperties.m index 090c28aa..2293ca0f 100644 --- a/SUPLA/_SALocation+CoreDataProperties.m +++ b/SUPLA/_SALocation+CoreDataProperties.m @@ -1,31 +1,32 @@ /* - Copyright (C) AC SOFTWARE SP. Z O.O. - - This program is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License - as published by the Free Software Foundation; either version 2 - of the License, or (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ +Copyright (C) AC SOFTWARE SP. Z O.O. + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ #import "_SALocation+CoreDataProperties.h" @implementation _SALocation (CoreDataProperties) + (NSFetchRequest<_SALocation *> *)fetchRequest { - return [[NSFetchRequest alloc] initWithEntityName:@"SALocation"]; + return [NSFetchRequest fetchRequestWithEntityName:@"SALocation"]; } @dynamic caption; @dynamic location_id; @dynamic visible; +@dynamic collapsed; @end From 4e44556a431d2a06707c8edb8cc51a7f366c201c Mon Sep 17 00:00:00 2001 From: Przemek Zygmunt Date: Fri, 1 Nov 2019 18:44:15 +0100 Subject: [PATCH 05/11] getRandom refactor --- SuplaApp.m | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/SuplaApp.m b/SuplaApp.m index 7bfdd551..31c33893 100644 --- a/SuplaApp.m +++ b/SuplaApp.m @@ -80,25 +80,25 @@ +(SAApp*)instance { return _Globals; } -+(void) getRandomKey:(char*)key keySize:(int)size forPrefKey:(NSString*)pref_key { ++(void) getRandom:(char*)key size:(int)size forPrefKey:(NSString*)pref_key { @synchronized(self) { - - NSData *KEY = [[NSUserDefaults standardUserDefaults] dataForKey:pref_key]; - if ( KEY == nil || [KEY length] != size ) { + NSData *randomData = [[NSUserDefaults standardUserDefaults] dataForKey:pref_key]; + + if ( randomData == nil || [randomData length] != size ) { - NSMutableData* newKEY = [NSMutableData dataWithCapacity:size]; + NSMutableData* newRandomData = [NSMutableData dataWithCapacity:size]; for( int i = 0 ; i < size; ++i ) { Byte random = arc4random(); - [newKEY appendBytes:(void*)&random length:1]; + [newRandomData appendBytes:(void*)&random length:1]; } - [[NSUserDefaults standardUserDefaults] setValue:newKEY forKey:pref_key]; - KEY = newKEY; + [[NSUserDefaults standardUserDefaults] setValue:newRandomData forKey:pref_key]; + randomData = newRandomData; }; - if ( KEY && [KEY length] == size ) { - [KEY getBytes:key length:size]; + if ( randomData && [randomData length] == size ) { + [randomData getBytes:key length:size]; } else { memset(key, 0, size); } @@ -109,11 +109,11 @@ +(void) getRandomKey:(char*)key keySize:(int)size forPrefKey:(NSString*)pref_key +(void) getClientGUID:(char[SUPLA_GUID_SIZE])guid { // TODO: Implement guid encryption with password based on device id - [SAApp getRandomKey:guid keySize:SUPLA_GUID_SIZE forPrefKey:@"client_guid"]; + [SAApp getRandom:guid size:SUPLA_GUID_SIZE forPrefKey:@"client_guid"]; } +(void) getAuthKey:(char [SUPLA_AUTHKEY_SIZE])auth_key { - [SAApp getRandomKey:auth_key keySize:SUPLA_AUTHKEY_SIZE forPrefKey:@"auth_key"]; + [SAApp getRandom:auth_key size:SUPLA_AUTHKEY_SIZE forPrefKey:@"auth_key"]; } -(int) getCfgVersion { From 2ee342b8399f2b55b3d5beb6412ac212be25c100 Mon Sep 17 00:00:00 2001 From: Przemek Zygmunt Date: Fri, 1 Nov 2019 20:06:21 +0100 Subject: [PATCH 06/11] NSData AES category + Test --- SUPLA.xcodeproj/project.pbxproj | 10 +++++ SUPLA/NSData+AES.h | 28 +++++++++++++ SUPLA/NSData+AES.m | 65 +++++++++++++++++++++++++++++++ SUPLATests/NSDataEncryptionTest.m | 57 +++++++++++++++++++++++++++ 4 files changed, 160 insertions(+) create mode 100644 SUPLA/NSData+AES.h create mode 100644 SUPLA/NSData+AES.m create mode 100644 SUPLATests/NSDataEncryptionTest.m diff --git a/SUPLA.xcodeproj/project.pbxproj b/SUPLA.xcodeproj/project.pbxproj index 0a8ee361..173fca33 100644 --- a/SUPLA.xcodeproj/project.pbxproj +++ b/SUPLA.xcodeproj/project.pbxproj @@ -89,6 +89,8 @@ 01EE9BB022BA4B050029A142 /* SAChannelExtendedValue+CoreDataProperties.m in Sources */ = {isa = PBXBuildFile; fileRef = 01EE9BAF22BA4B050029A142 /* SAChannelExtendedValue+CoreDataProperties.m */; }; 01EE9BBB22BA50D90029A142 /* SAChannelValueBase+CoreDataClass.m in Sources */ = {isa = PBXBuildFile; fileRef = 01EE9BB722BA50D90029A142 /* SAChannelValueBase+CoreDataClass.m */; }; 01EE9BBC22BA50D90029A142 /* SAChannelValueBase+CoreDataProperties.m in Sources */ = {isa = PBXBuildFile; fileRef = 01EE9BB822BA50D90029A142 /* SAChannelValueBase+CoreDataProperties.m */; }; + 01EFD94A236CA94400893489 /* NSData+AES.m in Sources */ = {isa = PBXBuildFile; fileRef = 01EFD949236CA94400893489 /* NSData+AES.m */; }; + 01EFD94C236CA9AE00893489 /* NSDataEncryptionTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 01EFD94B236CA9AE00893489 /* NSDataEncryptionTest.m */; }; 01F8856922E5E79100D18373 /* SATempHumidityMeasurementItem+CoreDataClass.m in Sources */ = {isa = PBXBuildFile; fileRef = 01F8855C22E5E79000D18373 /* SATempHumidityMeasurementItem+CoreDataClass.m */; }; 01F8856A22E5E79100D18373 /* SATempHumidityMeasurementItem+CoreDataProperties.m in Sources */ = {isa = PBXBuildFile; fileRef = 01F8856322E5E79100D18373 /* SATempHumidityMeasurementItem+CoreDataProperties.m */; }; 01F8856B22E5E79100D18373 /* SAThermostatMeasurementItem+CoreDataProperties.m in Sources */ = {isa = PBXBuildFile; fileRef = 01F8855522E5E79000D18373 /* SAThermostatMeasurementItem+CoreDataProperties.m */; }; @@ -591,6 +593,9 @@ 01EE9BB622BA50D90029A142 /* SAChannelValueBase+CoreDataClass.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "SAChannelValueBase+CoreDataClass.h"; sourceTree = ""; }; 01EE9BB722BA50D90029A142 /* SAChannelValueBase+CoreDataClass.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = "SAChannelValueBase+CoreDataClass.m"; sourceTree = ""; }; 01EE9BB822BA50D90029A142 /* SAChannelValueBase+CoreDataProperties.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = "SAChannelValueBase+CoreDataProperties.m"; sourceTree = ""; }; + 01EFD948236CA94400893489 /* NSData+AES.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "NSData+AES.h"; sourceTree = ""; }; + 01EFD949236CA94400893489 /* NSData+AES.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = "NSData+AES.m"; sourceTree = ""; }; + 01EFD94B236CA9AE00893489 /* NSDataEncryptionTest.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = NSDataEncryptionTest.m; sourceTree = ""; }; 01F8855522E5E79000D18373 /* SAThermostatMeasurementItem+CoreDataProperties.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = "SAThermostatMeasurementItem+CoreDataProperties.m"; sourceTree = ""; }; 01F8855622E5E79000D18373 /* SAImpulseCounterMeasurementItem+CoreDataClass.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = "SAImpulseCounterMeasurementItem+CoreDataClass.m"; sourceTree = ""; }; 01F8855722E5E79000D18373 /* SAImpulseCounterMeasurementItem+CoreDataProperties.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "SAImpulseCounterMeasurementItem+CoreDataProperties.h"; sourceTree = ""; }; @@ -1140,6 +1145,8 @@ 40A675851BA1BEBF004A51C4 /* UI */, 40A6757D1BA1A5B6004A51C4 /* SuplaApp.h */, 40A6757E1BA1A5B6004A51C4 /* SuplaApp.m */, + 01EFD948236CA94400893489 /* NSData+AES.h */, + 01EFD949236CA94400893489 /* NSData+AES.m */, 401CA1C01BA067DB00117AF4 /* AppDelegate.h */, 401CA1C11BA067DB00117AF4 /* AppDelegate.m */, 401CA1CC1BA067DB00117AF4 /* Images.xcassets */, @@ -1168,6 +1175,7 @@ 401CA1D81BA067DB00117AF4 /* SUPLATests */ = { isa = PBXGroup; children = ( + 01EFD94B236CA9AE00893489 /* NSDataEncryptionTest.m */, 012F722822DF3CF000E5F72E /* ChartFilterFieldTests.m */, 401CA1DB1BA067DB00117AF4 /* SUPLATests.m */, 401CA1D91BA067DB00117AF4 /* Supporting Files */, @@ -2038,6 +2046,7 @@ 019D22F0233CC2D000F17135 /* SAPreloader.m in Sources */, 40DE1A361BCD1B55004CF43B /* AboutVC.m in Sources */, 4017E12C1BB9CE2900570AC8 /* ChannelCell.m in Sources */, + 01EFD94A236CA94400893489 /* NSData+AES.m in Sources */, 01C1719222C7F3A2005983E1 /* SAElectricityMeasurementItem+CoreDataProperties.m in Sources */, 40AB8BDE1DCB32EB0030F3DE /* SARateApp.m in Sources */, 01C1719122C7F3A2005983E1 /* SAElectricityMeasurementItem+CoreDataClass.m in Sources */, @@ -2133,6 +2142,7 @@ buildActionMask = 2147483647; files = ( 401CA1DC1BA067DB00117AF4 /* SUPLATests.m in Sources */, + 01EFD94C236CA9AE00893489 /* NSDataEncryptionTest.m in Sources */, 012F722C22DF3E2300E5F72E /* ChartFilterFieldTests.m in Sources */, 0130894523395F4C00F46FCD /* ThermostatScheduleCfgTests.m in Sources */, 012FCBD323217DE000AC6FF6 /* ThermostatCalendarTests.m in Sources */, diff --git a/SUPLA/NSData+AES.h b/SUPLA/NSData+AES.h new file mode 100644 index 00000000..644e0bfd --- /dev/null +++ b/SUPLA/NSData+AES.h @@ -0,0 +1,28 @@ +/* +Copyright (C) AC SOFTWARE SP. Z O.O. + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#import + +NS_ASSUME_NONNULL_BEGIN + +@interface NSData (AES) +- (NSData *)aes128EncryptWithKey:(NSString *)key; +- (NSData *)aes128DecryptWithKey:(NSString *)key; +@end + +NS_ASSUME_NONNULL_END diff --git a/SUPLA/NSData+AES.m b/SUPLA/NSData+AES.m new file mode 100644 index 00000000..66b0ed04 --- /dev/null +++ b/SUPLA/NSData+AES.m @@ -0,0 +1,65 @@ +/* +Copyright (C) AC SOFTWARE SP. Z O.O. + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#import "NSData+AES.h" +#import + +@implementation NSData (AES) + +-(NSData *)aes128Operation:(CCOperation)operation withKey:(NSString *)key { + + while(key.length < 32) { + key = [NSString stringWithFormat:@"%@0", key]; + } + + key = [key substringToIndex:32]; + + size_t bufferSize = [self length] + kCCBlockSizeAES128 * 2; + void *buffer = malloc(bufferSize); + + NSData *_key = [key dataUsingEncoding:NSUTF8StringEncoding]; + + size_t encryptedSize = 0; + CCCryptorStatus cryptStatus = CCCrypt(operation, + kCCAlgorithmAES128, + kCCOptionPKCS7Padding, + [_key bytes], + [_key length], + nil, + [self bytes], + [self length], + buffer, + bufferSize, + &encryptedSize); + + if (cryptStatus == kCCSuccess && encryptedSize > 0) { + return [NSData dataWithBytesNoCopy:buffer length:encryptedSize]; + } + + free(buffer); + return nil; +} + +- (NSData *)aes128EncryptWithKey:(NSString *)key { + return [self aes128Operation:kCCEncrypt withKey:key]; +} + +- (NSData *)aes128DecryptWithKey:(NSString *)key { + return [self aes128Operation:kCCDecrypt withKey:key]; +} +@end diff --git a/SUPLATests/NSDataEncryptionTest.m b/SUPLATests/NSDataEncryptionTest.m new file mode 100644 index 00000000..54c5fa91 --- /dev/null +++ b/SUPLATests/NSDataEncryptionTest.m @@ -0,0 +1,57 @@ +/* +Copyright (C) AC SOFTWARE SP. Z O.O. + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#import +#import "NSData+AES.h" + +@interface NSDataEncryptionTest : XCTestCase + +@end + +@implementation NSDataEncryptionTest + +- (void)testEncryption { + + NSString *sourceText = @"ABCD"; + NSData *sourceData = [sourceText dataUsingEncoding:NSUTF8StringEncoding]; + + // Key is aligned to 32 characters + NSData *encrypted = [sourceData aes128EncryptWithKey:@"X"]; + XCTAssertNotNil(encrypted); + XCTAssertFalse([encrypted isEqualToData:sourceData]); + + NSData *decrypted = [encrypted aes128DecryptWithKey:@"X"]; + XCTAssertNotNil(decrypted); + XCTAssertFalse([encrypted isEqualToData:decrypted]); + XCTAssertTrue([decrypted isEqualToData:sourceData]); + + NSString *decryptedText = [[NSString alloc] + initWithData:decrypted encoding:NSUTF8StringEncoding]; + XCTAssertTrue([decryptedText isEqualToString:sourceText]); + + decrypted = [encrypted aes128DecryptWithKey:@"Y"]; + XCTAssertFalse([sourceData isEqualToData:decrypted]); + + decrypted = [encrypted aes128DecryptWithKey:@"X000000000000000000000000000000Y"]; + XCTAssertFalse([sourceData isEqualToData:decrypted]); + + decrypted = [encrypted aes128DecryptWithKey:@"X0000000000000000000000000000000Y"]; + XCTAssertTrue([sourceData isEqualToData:decrypted]); +} + +@end From 103c55fc74ca0410b933e0c1abfbfadfe9f875ab Mon Sep 17 00:00:00 2001 From: Przemek Zygmunt Date: Fri, 1 Nov 2019 20:33:10 +0100 Subject: [PATCH 07/11] Encrypt GUID and AuthKey with device unique id --- SUPLA/NSData+AES.h | 3 +++ SUPLA/NSData+AES.m | 12 ++++++++++++ SuplaApp.m | 36 ++++++++++++++++++++++++------------ 3 files changed, 39 insertions(+), 12 deletions(-) diff --git a/SUPLA/NSData+AES.h b/SUPLA/NSData+AES.h index 644e0bfd..14da265c 100644 --- a/SUPLA/NSData+AES.h +++ b/SUPLA/NSData+AES.h @@ -23,6 +23,9 @@ NS_ASSUME_NONNULL_BEGIN @interface NSData (AES) - (NSData *)aes128EncryptWithKey:(NSString *)key; - (NSData *)aes128DecryptWithKey:(NSString *)key; + +- (NSData *)aes128EncryptWithDeviceUniqueId; +- (NSData *)aes128DecryptWithDeviceUniqueId; @end NS_ASSUME_NONNULL_END diff --git a/SUPLA/NSData+AES.m b/SUPLA/NSData+AES.m index 66b0ed04..85b45628 100644 --- a/SUPLA/NSData+AES.m +++ b/SUPLA/NSData+AES.m @@ -17,6 +17,7 @@ */ #import "NSData+AES.h" +#import #import @implementation NSData (AES) @@ -62,4 +63,15 @@ - (NSData *)aes128EncryptWithKey:(NSString *)key { - (NSData *)aes128DecryptWithKey:(NSString *)key { return [self aes128Operation:kCCDecrypt withKey:key]; } + +- (NSData *)aes128EncryptWithDeviceUniqueId { + NSString *key = [[[UIDevice currentDevice] identifierForVendor] UUIDString]; + return [self aes128EncryptWithKey:key]; +} + +- (NSData *)aes128DecryptWithDeviceUniqueId { + NSString *key = [[[UIDevice currentDevice] identifierForVendor] UUIDString]; + return [self aes128DecryptWithKey:key]; + +} @end diff --git a/SuplaApp.m b/SuplaApp.m index 31c33893..0c445522 100644 --- a/SuplaApp.m +++ b/SuplaApp.m @@ -19,7 +19,7 @@ #import "SuplaApp.h" #import "Database.h" - +#import "NSData+AES.h" static SAApp* _Globals = nil; @@ -80,25 +80,38 @@ +(SAApp*)instance { return _Globals; } -+(void) getRandom:(char*)key size:(int)size forPrefKey:(NSString*)pref_key { +-(void) encryptData:(NSData *)data andSaveWithPrefKey:(NSString *)pref_key { + @synchronized(self) { + data = [data aes128EncryptWithDeviceUniqueId]; + [[NSUserDefaults standardUserDefaults] setValue:data forKey:pref_key]; + [[NSUserDefaults standardUserDefaults] setBool:true forKey:[NSString stringWithFormat:@"%@_encrypted", pref_key]]; + } +} + +-(void) getRandom:(char*)key size:(int)size forPrefKey:(NSString*)pref_key { @synchronized(self) { - NSData *randomData = [[NSUserDefaults standardUserDefaults] dataForKey:pref_key]; + NSData *data = [[NSUserDefaults standardUserDefaults] dataForKey:pref_key]; - if ( randomData == nil || [randomData length] != size ) { - + if ([[NSUserDefaults standardUserDefaults] boolForKey:[NSString stringWithFormat:@"%@_encrypted", pref_key]]) { + data = [data aes128DecryptWithDeviceUniqueId]; + } else { + [self encryptData:data andSaveWithPrefKey:pref_key]; + } + + if ( data == nil || [data length] != size ) { NSMutableData* newRandomData = [NSMutableData dataWithCapacity:size]; for( int i = 0 ; i < size; ++i ) { Byte random = arc4random(); [newRandomData appendBytes:(void*)&random length:1]; } - [[NSUserDefaults standardUserDefaults] setValue:newRandomData forKey:pref_key]; - randomData = newRandomData; + [self encryptData:newRandomData andSaveWithPrefKey:pref_key]; + data = newRandomData; }; - if ( randomData && [randomData length] == size ) { - [randomData getBytes:key length:size]; + if ( data && [data length] == size ) { + [data getBytes:key length:size]; } else { memset(key, 0, size); } @@ -108,12 +121,11 @@ +(void) getRandom:(char*)key size:(int)size forPrefKey:(NSString*)pref_key { } +(void) getClientGUID:(char[SUPLA_GUID_SIZE])guid { - // TODO: Implement guid encryption with password based on device id - [SAApp getRandom:guid size:SUPLA_GUID_SIZE forPrefKey:@"client_guid"]; + [[self instance] getRandom:guid size:SUPLA_GUID_SIZE forPrefKey:@"client_guid"]; } +(void) getAuthKey:(char [SUPLA_AUTHKEY_SIZE])auth_key { - [SAApp getRandom:auth_key size:SUPLA_AUTHKEY_SIZE forPrefKey:@"auth_key"]; + [[self instance] getRandom:auth_key size:SUPLA_AUTHKEY_SIZE forPrefKey:@"auth_key"]; } -(int) getCfgVersion { From 2a66d0ade0105debe41a9f346eb1e18d8b3b9186 Mon Sep 17 00:00:00 2001 From: Przemek Zygmunt Date: Fri, 1 Nov 2019 20:33:29 +0100 Subject: [PATCH 08/11] Version increment --- SUPLA.xcodeproj/project.pbxproj | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/SUPLA.xcodeproj/project.pbxproj b/SUPLA.xcodeproj/project.pbxproj index 173fca33..4a8cf6c6 100644 --- a/SUPLA.xcodeproj/project.pbxproj +++ b/SUPLA.xcodeproj/project.pbxproj @@ -2527,7 +2527,7 @@ "$(inherited)", "$(PROJECT_DIR)/SUPLA/lib", ); - MARKETING_VERSION = 2.3.0; + MARKETING_VERSION = 2.3.1; PRODUCT_BUNDLE_IDENTIFIER = com.acsoftware.ios.supla; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_OBJC_BRIDGING_HEADER = "SUPLA/SUPLA-Bridging-Header.h"; @@ -2554,7 +2554,7 @@ "$(inherited)", "$(PROJECT_DIR)/SUPLA/lib", ); - MARKETING_VERSION = 2.3.0; + MARKETING_VERSION = 2.3.1; PRODUCT_BUNDLE_IDENTIFIER = com.acsoftware.ios.supla; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_OBJC_BRIDGING_HEADER = "SUPLA/SUPLA-Bridging-Header.h"; From 9fc03fe734576c119f36f786aa56759134ac59ae Mon Sep 17 00:00:00 2001 From: Przemek Zygmunt Date: Fri, 1 Nov 2019 20:41:58 +0100 Subject: [PATCH 09/11] kCCBlockSizeAES128 * 1 is sufficient --- SUPLA/NSData+AES.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SUPLA/NSData+AES.m b/SUPLA/NSData+AES.m index 85b45628..c7e3ae99 100644 --- a/SUPLA/NSData+AES.m +++ b/SUPLA/NSData+AES.m @@ -30,7 +30,7 @@ -(NSData *)aes128Operation:(CCOperation)operation withKey:(NSString *)key { key = [key substringToIndex:32]; - size_t bufferSize = [self length] + kCCBlockSizeAES128 * 2; + size_t bufferSize = [self length] + kCCBlockSizeAES128; void *buffer = malloc(bufferSize); NSData *_key = [key dataUsingEncoding:NSUTF8StringEncoding]; From ab116c29631df14e6a9d494f004b79d16ac8fe3f Mon Sep 17 00:00:00 2001 From: Przemek Zygmunt Date: Fri, 1 Nov 2019 20:49:05 +0100 Subject: [PATCH 10/11] "key" renamed to "password" --- SUPLA/NSData+AES.h | 4 ++-- SUPLA/NSData+AES.m | 28 +++++++++++++++------------- SUPLATests/NSDataEncryptionTest.m | 10 +++++----- 3 files changed, 22 insertions(+), 20 deletions(-) diff --git a/SUPLA/NSData+AES.h b/SUPLA/NSData+AES.h index 14da265c..14c59ef5 100644 --- a/SUPLA/NSData+AES.h +++ b/SUPLA/NSData+AES.h @@ -21,8 +21,8 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. NS_ASSUME_NONNULL_BEGIN @interface NSData (AES) -- (NSData *)aes128EncryptWithKey:(NSString *)key; -- (NSData *)aes128DecryptWithKey:(NSString *)key; +- (NSData *)aes128EncryptWithPassword:(NSString *)password; +- (NSData *)aes128DecryptWithPassword:(NSString *)password; - (NSData *)aes128EncryptWithDeviceUniqueId; - (NSData *)aes128DecryptWithDeviceUniqueId; diff --git a/SUPLA/NSData+AES.m b/SUPLA/NSData+AES.m index c7e3ae99..21ec1361 100644 --- a/SUPLA/NSData+AES.m +++ b/SUPLA/NSData+AES.m @@ -22,18 +22,20 @@ @implementation NSData (AES) --(NSData *)aes128Operation:(CCOperation)operation withKey:(NSString *)key { +-(NSData *)aes128Operation:(CCOperation)operation withPassword:(NSString *)password { - while(key.length < 32) { - key = [NSString stringWithFormat:@"%@0", key]; + // *Password + // This is not a good implementation but sufficient for current use + while(password.length < 32) { + password = [NSString stringWithFormat:@"%@0", password]; } - key = [key substringToIndex:32]; + password = [password substringToIndex:32]; size_t bufferSize = [self length] + kCCBlockSizeAES128; void *buffer = malloc(bufferSize); - NSData *_key = [key dataUsingEncoding:NSUTF8StringEncoding]; + NSData *_key = [password dataUsingEncoding:NSUTF8StringEncoding]; size_t encryptedSize = 0; CCCryptorStatus cryptStatus = CCCrypt(operation, @@ -56,22 +58,22 @@ -(NSData *)aes128Operation:(CCOperation)operation withKey:(NSString *)key { return nil; } -- (NSData *)aes128EncryptWithKey:(NSString *)key { - return [self aes128Operation:kCCEncrypt withKey:key]; +- (NSData *)aes128EncryptWithPassword:(NSString *)password { + return [self aes128Operation:kCCEncrypt withPassword:password]; } -- (NSData *)aes128DecryptWithKey:(NSString *)key { - return [self aes128Operation:kCCDecrypt withKey:key]; +- (NSData *)aes128DecryptWithPassword:(NSString *)password { + return [self aes128Operation:kCCDecrypt withPassword:password]; } - (NSData *)aes128EncryptWithDeviceUniqueId { - NSString *key = [[[UIDevice currentDevice] identifierForVendor] UUIDString]; - return [self aes128EncryptWithKey:key]; + NSString *pwd = [[[UIDevice currentDevice] identifierForVendor] UUIDString]; + return [self aes128EncryptWithPassword:pwd]; } - (NSData *)aes128DecryptWithDeviceUniqueId { - NSString *key = [[[UIDevice currentDevice] identifierForVendor] UUIDString]; - return [self aes128DecryptWithKey:key]; + NSString *pwd = [[[UIDevice currentDevice] identifierForVendor] UUIDString]; + return [self aes128DecryptWithPassword:pwd]; } @end diff --git a/SUPLATests/NSDataEncryptionTest.m b/SUPLATests/NSDataEncryptionTest.m index 54c5fa91..13ef7a4b 100644 --- a/SUPLATests/NSDataEncryptionTest.m +++ b/SUPLATests/NSDataEncryptionTest.m @@ -31,11 +31,11 @@ - (void)testEncryption { NSData *sourceData = [sourceText dataUsingEncoding:NSUTF8StringEncoding]; // Key is aligned to 32 characters - NSData *encrypted = [sourceData aes128EncryptWithKey:@"X"]; + NSData *encrypted = [sourceData aes128EncryptWithPassword:@"X"]; XCTAssertNotNil(encrypted); XCTAssertFalse([encrypted isEqualToData:sourceData]); - NSData *decrypted = [encrypted aes128DecryptWithKey:@"X"]; + NSData *decrypted = [encrypted aes128DecryptWithPassword:@"X"]; XCTAssertNotNil(decrypted); XCTAssertFalse([encrypted isEqualToData:decrypted]); XCTAssertTrue([decrypted isEqualToData:sourceData]); @@ -44,13 +44,13 @@ - (void)testEncryption { initWithData:decrypted encoding:NSUTF8StringEncoding]; XCTAssertTrue([decryptedText isEqualToString:sourceText]); - decrypted = [encrypted aes128DecryptWithKey:@"Y"]; + decrypted = [encrypted aes128DecryptWithPassword:@"Y"]; XCTAssertFalse([sourceData isEqualToData:decrypted]); - decrypted = [encrypted aes128DecryptWithKey:@"X000000000000000000000000000000Y"]; + decrypted = [encrypted aes128DecryptWithPassword:@"X000000000000000000000000000000Y"]; XCTAssertFalse([sourceData isEqualToData:decrypted]); - decrypted = [encrypted aes128DecryptWithKey:@"X0000000000000000000000000000000Y"]; + decrypted = [encrypted aes128DecryptWithPassword:@"X0000000000000000000000000000000Y"]; XCTAssertTrue([sourceData isEqualToData:decrypted]); } From a906af9fba5bff454bdaf74868c803987f6fa0d7 Mon Sep 17 00:00:00 2001 From: Przemek Zygmunt Date: Fri, 1 Nov 2019 21:14:59 +0100 Subject: [PATCH 11/11] Set %@_encrypted to false when encryption failed --- SuplaApp.m | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/SuplaApp.m b/SuplaApp.m index 0c445522..1a9c1811 100644 --- a/SuplaApp.m +++ b/SuplaApp.m @@ -82,9 +82,10 @@ +(SAApp*)instance { -(void) encryptData:(NSData *)data andSaveWithPrefKey:(NSString *)pref_key { @synchronized(self) { - data = [data aes128EncryptWithDeviceUniqueId]; - [[NSUserDefaults standardUserDefaults] setValue:data forKey:pref_key]; - [[NSUserDefaults standardUserDefaults] setBool:true forKey:[NSString stringWithFormat:@"%@_encrypted", pref_key]]; + NSData *encryptedData = [data aes128EncryptWithDeviceUniqueId]; + NSUserDefaults *ud = [NSUserDefaults standardUserDefaults]; + [ud setValue:(encryptedData != nil ? encryptedData : data) forKey:pref_key]; + [ud setBool:(encryptedData != nil) forKey:[NSString stringWithFormat:@"%@_encrypted", pref_key]]; } }