forked from hnzhangshilong/TeamTalk
-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathTTHttpsRequest.m
287 lines (200 loc) · 9.54 KB
/
TTHttpsRequest.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
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
//
// TTHttpsRequest.m
// TeamTalk
//
// Created by Michael Scofield on 2015-01-29.
// Copyright (c) 2015 Michael Hu. All rights reserved.
//
#import "TTHttpsRequest.h"
@implementation TTHttpsRequest
+ (SecIdentityRef)identityWithTrust
{
SecIdentityRef identity = NULL;
SecTrustRef trust = NULL;
//绑定证书,证书放在Resources文件夹中
//NSData *PKCS12Data = [NSData dataWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"yunwei" ofType:@"p12"]];//证书文件名和文件类型
NSData *PKCS12Data = [NSData dataWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"yunwei" ofType:@"p12"]];//证书文件名和文件类型
if (!PKCS12Data) {
//没有文件证书
NSLog(@"Can not load pkcs12 cert , plz check !");
return nil;
}
//NSLog(@"pkcs12Data is %@",PKCS12Data);
[[self class] extractIdentity:&identity andTrust:&trust fromPKCS12Data:PKCS12Data];
return identity;
}
+ (SecIdentityRef)identityWithCert
{
NSString *path = [[NSBundle mainBundle]pathForResource:@"yunwei" ofType:@"p12"];
NSData *p12data = [NSData dataWithContentsOfFile:path];
SecIdentityRef identity = NULL; SecCertificateRef certificate = NULL;
if (!p12data) {
NSLog(@"Can not load pkcs12 cert , plz check !");
return nil;
}
[[self class] identity:&identity andCertificate:&certificate fromPKCS12Data:p12data];
return identity;
}
+ (BOOL)extractIdentity:(SecIdentityRef *)outIdentity andTrust:(SecTrustRef*)outTrust fromPKCS12Data:(NSData *)inPKCS12Data
{
OSStatus securityError = errSecSuccess;
NSDictionary *optionsDictionary = [NSDictionary dictionaryWithObject:@"1234" forKey:(__bridge id)kSecImportExportPassphrase];
CFArrayRef items = CFArrayCreate(NULL, 0, 0, NULL); securityError = SecPKCS12Import((__bridge CFDataRef)inPKCS12Data,(__bridge CFDictionaryRef)optionsDictionary,&items);
if (securityError == 0) {
CFDictionaryRef myIdentityAndTrust = CFArrayGetValueAtIndex (items, 0);
const void *tempIdentity = NULL;
tempIdentity = CFDictionaryGetValue (myIdentityAndTrust, kSecImportItemIdentity);
*outIdentity = (SecIdentityRef)tempIdentity;
const void *tempTrust = NULL;
tempTrust = CFDictionaryGetValue (myIdentityAndTrust, kSecImportItemTrust);
*outTrust = (SecTrustRef)tempTrust;
} else {
NSLog(@"SSSSLLLL Failed with error code %d",(int)securityError);
return NO;
}
return YES;
}
+ (BOOL)identity:(SecIdentityRef *)outIdentity andCertificate:(SecCertificateRef*)outCert fromPKCS12Data:(NSData *)inPKCS12Data
{
//NSLog(@"验证证书");
OSStatus securityError = errSecSuccess;
NSDictionary *optionsDictionary = [NSDictionary dictionaryWithObject:@"1234" forKey:(__bridge id)kSecImportExportPassphrase];
CFArrayRef items = CFArrayCreate(NULL, 0, 0, NULL); securityError = SecPKCS12Import((__bridge CFDataRef)inPKCS12Data,(__bridge CFDictionaryRef)optionsDictionary,&items);
if (securityError == 0) {
CFDictionaryRef myIdentityAndTrust = CFArrayGetValueAtIndex (items, 0);
const void *tempIdentity = NULL;
tempIdentity = CFDictionaryGetValue (myIdentityAndTrust, kSecImportItemIdentity);
*outIdentity = (SecIdentityRef)tempIdentity;
const void *tempCert = NULL;
tempCert = CFDictionaryGetValue (myIdentityAndTrust, kSecImportItemCertChain);
*outCert = (SecCertificateRef)tempCert;
} else {
NSLog(@"SSSSLLLL Failed with error code %d",(int)securityError);
return NO;
}
//NSLog(@"验证完毕");
return YES;
}
@end
#define kOpCenterAPI_url @"https://mogujie.org"
@implementation opURLProtocal
{
//可以在此定义数据容器,连接等
}
static NSString *cachingURLHeader = @"hadInURLProtocal";
- (void)startLoading
{
//NSLog(@"1.start loading");
//可以这样子拿到原来的请求,用以拼装自己的请求
NSMutableURLRequest *proxyRequest = [self.request mutableCopy];
//NSLog(@"protocal url is %@",[[proxyRequest URL] absoluteString]);
[proxyRequest setValue:@"" forHTTPHeaderField:cachingURLHeader];
//connection = [NSURLConnection connectionWithRequest:proxyRequest delegate:self];
connection = [[NSURLConnection alloc] initWithRequest:proxyRequest delegate:self startImmediately:NO];
[connection start];
}
- (void)stopLoading
{
[connection cancel];
}
- (NSURLRequest *)connection:(NSURLConnection *)connection willSendRequest:(NSURLRequest *)request redirectResponse:(NSURLResponse *)response
{
if(response!=nil)
{
NSMutableURLRequest *redirectableRequest = [request mutableCopy];
[redirectableRequest setValue:nil forHTTPHeaderField:cachingURLHeader];
[self.client URLProtocol:self wasRedirectedToRequest:redirectableRequest redirectResponse:response];
return redirectableRequest ;
}
return request;
}
- (BOOL)connection:(NSURLConnection *)connection canAuthenticateAgainstProtectionSpace:(NSURLProtectionSpace *)protectionSpace {
//NSLog(@"3.We are checking protection Space!");
return YES;
if([protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust])
{
//NSLog(@"Can Auth Secure Requestes!");
return YES;
}
else if([protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodHTTPBasic])
{
//NSLog(@"Can Auth Basic Requestes!");
return YES;
//return NO;
}
NSLog(@"Cannot Auth!");
return NO;
}
- (void)connection:(NSURLConnection *)connection didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge
{
OSStatus err;
NSURLCredential * credential;
assert(challenge != nil);
credential = nil;
// Handle ServerTrust and Client Certificate challenges
NSString *authenticationMethod = [[challenge protectionSpace] authenticationMethod];
if ([authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust]) {
//NSLog(@"Trust Challange");
SecTrustResultType trustResultType;
err = SecTrustEvaluate(challenge.protectionSpace.serverTrust, &trustResultType);
//NSLog(@"SecTrustResult %u %d",trustResultType, (int)err);
if (trustResultType == kSecTrustResultProceed || trustResultType == kSecTrustResultUnspecified) {
credential = [NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust];
assert(credential != nil);
}
} else {
credential = [NSURLCredential credentialWithIdentity:[TTHttpsRequest identityWithCert] certificates:nil persistence:NSURLCredentialPersistencePermanent]; //到呢一步,certificates需要喺nil先过到
}
//NSLog(@"credential is %@",credential);
[challenge.sender useCredential:credential forAuthenticationChallenge:challenge];
//[protocol resolveAuthenticationChallenge:challenge withCredential:credential];
}
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
{
//这里是收到响应的头部信息,比如HTTP Header,可视情况做对self.client做相应操作,也可以不做处理
//NSLog(@"5.didReceiveResponse lalala");
//NSLog(@"response is %@",response);
[self.client URLProtocol:self didReceiveResponse:response cacheStoragePolicy:NSURLCacheStorageNotAllowed];
}
//这几个不是Protocol的方法,是自发起的URLConnection的回调
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)sourceData
{
//NSLog(@"sourceData is %@",sourceData);
//此方法会收到一部分或者全部的数据,可以这样子丢给原始请求的发起者
//NSLog(@"6.in didReceiveData method");
if (proRespData == nil) {
proRespData = [sourceData mutableCopy];
} else {
[proRespData appendData:sourceData];
}
}
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
{
//和上一个方法类似,这里作为错误通知
//NSLog(@"7.1in didFailWithError method %@",error);
[self.client URLProtocol:self didFailWithError:error];
//这里可以弹出一个错误提示
// [toastView hideToast];
// NSString *msg = [@"网络错误 - " stringByAppendingString:[error description]];
// [toastView showToastWithOK:msg];
return;
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
NSData *getData = proRespData ;
[self.client URLProtocol:self didLoadData:getData];
[self.client URLProtocolDidFinishLoading:self];
}
+ (BOOL)canInitWithRequest:(NSURLRequest *)request
{
//根据request来决定要不要劫持
//需要特别注意的是,如果你用NSURLConnection来发起代理请求,那么那个代理请求的request也同样会经过这里来做判决,所以一定要判断是不是代理请求,然后返回NO
if ([request.URL.absoluteString rangeOfString:kOpCenterAPI_url].location != NSNotFound && [request valueForHTTPHeaderField:cachingURLHeader] == nil) return YES;
return NO;
}
+ (NSURLRequest *)canonicalRequestForRequest:(NSURLRequest *)request
{
//这里是干嘛的,我还没研究清楚,就简单的返回了原始值,有兴趣的话你可以研究一下
return request;
}
@end