-
Notifications
You must be signed in to change notification settings - Fork 9
/
FileManager.m
243 lines (200 loc) · 7.32 KB
/
FileManager.m
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
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
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
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
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
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
//
// FileManager.m
// MyKeePass
//
// Created by Qiang Yu on 3/3/10.
// Copyright 2010 Qiang Yu. All rights reserved.
//
#import <CommonCrypto/CommonDigest.h>
//Keepass2 utils
#import <Utils.h>
#import "FileManager.h"
#import "ASIHTTPRequest.h"
#import "MyKeePassAppDelegate.h"
#import "ActivityView.h"
@interface FileManager(PrivateMethods)
-(id<KdbTree>) readFileHelp:(NSString *) fileName withPassword:(NSString *)password;
@end
@implementation FileManager
@synthesize _kdbReader;
@synthesize _editable;
@synthesize _filename;
@synthesize _password;
@synthesize _dirty;
@synthesize _remoteFiles;
#define KDB_PATH "Passwords"
#define DOWNLOAD_PATH "Download"
#define KDB1_SUFFIX ".kdb"
#define KDB2_SUFFIX ".kdbx"
static NSString * DATA_DIR;
static NSString * DOWNLOAD_DIR;
static NSString * DOWNLOAD_CONFIG;
+(void)initialize{
if ( self == [FileManager class] ) {
#if TARGET_IPHONE_SIMULATOR
DATA_DIR = @"/Volumes/Users/qiang/Desktop/";
DOWNLOAD_DIR = DATA_DIR;
#else
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
DATA_DIR = [[(NSString *)[paths objectAtIndex:0] stringByAppendingPathComponent:@KDB_PATH] retain];
DOWNLOAD_DIR = [[(NSString *)[paths objectAtIndex:0] stringByAppendingPathComponent:@DOWNLOAD_PATH] retain];
NSFileManager * fileManager = [NSFileManager defaultManager];
if(![fileManager fileExistsAtPath:DATA_DIR]){
[fileManager createDirectoryAtPath:DATA_DIR withIntermediateDirectories:YES attributes:nil error:nil];
}
if(![fileManager fileExistsAtPath:DOWNLOAD_DIR]){
[fileManager createDirectoryAtPath:DOWNLOAD_DIR withIntermediateDirectories:YES attributes:nil error:nil];
}
#endif
DOWNLOAD_CONFIG = [[DOWNLOAD_DIR stringByAppendingPathComponent:@".download"] retain];
if(![[NSFileManager defaultManager] fileExistsAtPath:DOWNLOAD_CONFIG]){
NSDictionary * dic = [[NSDictionary alloc]init];
[dic writeToFile:DOWNLOAD_CONFIG atomically:YES];
[dic release];
}
}
}
+(NSString *)dataDir{
return DATA_DIR;
}
-(id)init{
if(self = [super init]){
self._remoteFiles = [NSMutableDictionary dictionaryWithContentsOfFile:DOWNLOAD_CONFIG];
}
return self;
}
-(void)dealloc{
[_remoteFiles release];
[_password release];
[_filename release];
[_kdbReader release];
[super dealloc];
}
-(id<KdbTree>) readFile:(NSString *) fileName withPassword:(NSString *)password{
self._filename = fileName;
return [self readFileHelp:[FileManager getFullFileName:fileName] withPassword:password];
}
-(id<KdbTree>) readFileHelp:(NSString *) fileName withPassword:(NSString *)password{
self._password = password;
self._dirty = NO;
WrapperNSData * source = [[WrapperNSData alloc]initWithContentsOfMappedFile:fileName];
self._kdbReader = nil;
_kdbReader = [KdbReaderFactory newKdbReader:source];
//
// only kdb3 file is editable so far
//
_editable = [_kdbReader isKindOfClass:[Kdb3Reader class]];
[_kdbReader load:source withPassword:password];
[source release];
return [_kdbReader getKdbTree];
}
+(NSString *)getTempFileNameFromURL:(NSString *)url{
ByteBuffer * buffer = [Utils createByteBufferForString:url coding:NSUTF8StringEncoding];
uint8_t hash[20];
CC_SHA1(buffer._bytes, buffer._size, hash);
[buffer release];
NSString * filename = [NSString stringWithFormat:@"%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X",
hash[0], hash[1], hash[2], hash[3], hash[4], hash[5], hash[6], hash[7], hash[8], hash[9],
hash[10], hash[11], hash[12], hash[13], hash[14], hash[15], hash[16], hash[17], hash[18], hash[19], nil];
return [DOWNLOAD_DIR stringByAppendingPathComponent:filename];
}
-(id<KdbTree>) readRemoteFile:(NSString *)filename withPassword:(NSString *)password useCached:(BOOL)useCached username:(NSString *)username userpass:(NSString *)userpass domain:(NSString *)domain{
self._filename = filename;
NSString * url = [self getURLForRemoteFile:filename];
if(!url) @throw [NSException exceptionWithName:@"DownloadError" reason:@"DownloadError" userInfo:nil];
NSString * cacheFileName = [FileManager getTempFileNameFromURL:url];
NSString * tmp = [cacheFileName stringByAppendingString:@".tmp"];
NSFileManager * fileManager = [NSFileManager defaultManager];
if([fileManager fileExistsAtPath:cacheFileName]&&useCached){
id<KdbTree> tree = [self readFileHelp:cacheFileName withPassword:password];
_editable = NO;
return tree;
}
ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:[NSURL URLWithString:url]];
[request setDownloadDestinationPath:tmp];
if([username length])
[request setUsername:username];
if([userpass length])
[request setPassword:userpass];
if([domain length])
[request setDomain:domain];
[request startSynchronous];
int statusCode = [request responseStatusCode];
if(statusCode!=200){
if(statusCode==401){
@throw [NSException exceptionWithName:@"RemoteAuthenticationError" reason:@"RemoteAuthenticationError" userInfo:nil];
}else{
@throw [NSException exceptionWithName:@"DownloadError" reason:@"DownloadError" userInfo:nil];
}
}
[[NSFileManager defaultManager] removeItemAtPath:cacheFileName error:nil];
[[NSFileManager defaultManager] moveItemAtPath:tmp toPath:cacheFileName error:nil];
id<KdbTree> tree = [self readFileHelp:cacheFileName withPassword:password];
//remote file is not editable, yet
_editable = NO;
return tree;
}
-(void)getKDBFiles:(NSMutableArray *)list{
[list removeAllObjects];
//kdb/kdbx files
NSFileManager * fileManager = [NSFileManager defaultManager];
NSArray * contents = [fileManager contentsOfDirectoryAtPath:DATA_DIR error:nil];
for(NSString * fileName in contents){
if(![fileName hasPrefix:@"."]){
[list addObject:fileName];
}
}
[list sortUsingSelector:@selector(caseInsensitiveCompare:)];
}
-(void)getRemoteFiles:(NSMutableArray *)list{
[list removeAllObjects];
[list addObjectsFromArray:[_remoteFiles keysSortedByValueUsingSelector:@selector(caseInsensitiveCompare:)]];
[list sortUsingSelector:@selector(compare:)];
}
-(void)addRemoteFile:(NSString *)name Url:(NSString *)url{
[_remoteFiles setObject:url forKey:name];
[_remoteFiles writeToFile:DOWNLOAD_CONFIG atomically:YES];
}
-(NSString *)getURLForRemoteFile:(NSString *)name{
return [_remoteFiles objectForKey:name];
}
-(void)deleteLocalFile:(NSString *)filename{
[[NSFileManager defaultManager] removeItemAtPath:[FileManager getFullFileName:filename] error:nil];
}
-(void)deleteRemoteFile:(NSString *)name{
[_remoteFiles removeObjectForKey:name];
[_remoteFiles writeToFile:DOWNLOAD_CONFIG atomically:YES];
}
-(NSUInteger) getKDBVersion{
if([_kdbReader isKindOfClass:[Kdb3Reader class]]){
return KDB_VERSION1;
}else{
return KDB_VERSION2;
}
}
-(void)save{
if(!_dirty) return;
if([_kdbReader isKindOfClass:[Kdb3Reader class]]){
Kdb3Writer * writer = nil;
@try{
writer = [[Kdb3Writer alloc]init];
[writer persist:[_kdbReader getKdbTree] file:[FileManager getFullFileName:_filename] withPassword:_password];
_dirty = NO;
}@finally {
[writer release];
}
}
}
+(NSString *)getFullFileName:(NSString *)filename{
return [DATA_DIR stringByAppendingPathComponent:filename];
}
+(void)newKdb3File:(NSString *)filename withPassword:(NSString *)password{
Kdb3Writer * writer = nil;
@try{
writer = [[Kdb3Writer alloc]init];
[writer newFile:[FileManager getFullFileName:filename] withPassword:password];
}@finally {
[writer release];
}
}
@end