mirror of https://github.com/oxen-io/session-ios
You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
165 lines
6.1 KiB
Objective-C
165 lines
6.1 KiB
Objective-C
#import "HttpRequest.h"
|
|
#import "Util.h"
|
|
#import "CryptoTools.h"
|
|
#import "Constraints.h"
|
|
#import "HttpRequestOrResponse.h"
|
|
|
|
@interface HttpRequest ()
|
|
@property NSString* method;
|
|
@property NSString* location;
|
|
@property NSString* optionalBody;
|
|
@property NSDictionary* headers;
|
|
|
|
@end
|
|
|
|
@implementation HttpRequest
|
|
|
|
+(HttpRequest*)httpRequestWithMethod:(NSString*)method andLocation:(NSString*)location andHeaders:(NSDictionary*)headers andOptionalBody:(NSString*)optionalBody {
|
|
require(method != nil);
|
|
require(location != nil);
|
|
require(headers != nil);
|
|
require((optionalBody == nil) == (headers[@"Content-Length"] == nil));
|
|
require(optionalBody == nil || [[@(optionalBody.length) description] isEqualToString:headers[@"Content-Length"]]);
|
|
|
|
HttpRequest* s = [HttpRequest new];
|
|
s->_method = method;
|
|
s->_location = location;
|
|
s->_optionalBody = optionalBody;
|
|
s->_headers = headers;
|
|
return s;
|
|
}
|
|
+(HttpRequest*)httpRequestUnauthenticatedWithMethod:(NSString*)method
|
|
andLocation:(NSString*)location
|
|
andOptionalBody:(NSString*)optionalBody {
|
|
require(method != nil);
|
|
require(location != nil);
|
|
|
|
NSMutableDictionary* headers = [NSMutableDictionary dictionary];
|
|
if (optionalBody != nil) {
|
|
headers[@"Content-Length"] = [@(optionalBody.length) stringValue];
|
|
}
|
|
|
|
HttpRequest* s = [HttpRequest new];
|
|
s->_method = method;
|
|
s->_location = location;
|
|
s->_optionalBody = optionalBody;
|
|
s->_headers = headers;
|
|
return s;
|
|
}
|
|
+(HttpRequest*)httpRequestWithBasicAuthenticationAndMethod:(NSString*)method
|
|
andLocation:(NSString*)location
|
|
andOptionalBody:(NSString*)optionalBody
|
|
andLocalNumber:(PhoneNumber*)localNumber
|
|
andPassword:(NSString*)password {
|
|
require(method != nil);
|
|
require(location != nil);
|
|
require(password != nil);
|
|
require(localNumber != nil);
|
|
|
|
NSMutableDictionary* headers = [NSMutableDictionary dictionary];
|
|
if (optionalBody != nil) {
|
|
headers[@"Content-Length"] = [@(optionalBody.length) stringValue];
|
|
}
|
|
headers[@"Authorization"] = [HttpRequest computeBasicAuthorizationTokenForLocalNumber:localNumber andPassword:password];
|
|
|
|
HttpRequest* s = [HttpRequest new];
|
|
s->_method = method;
|
|
s->_location = location;
|
|
s->_optionalBody = optionalBody;
|
|
s->_headers = headers;
|
|
return s;
|
|
}
|
|
+(HttpRequest*)httpRequestWithOtpAuthenticationAndMethod:(NSString*)method
|
|
andLocation:(NSString*)location
|
|
andOptionalBody:(NSString*)optionalBody
|
|
andLocalNumber:(PhoneNumber*)localNumber
|
|
andPassword:(NSString*)password
|
|
andCounter:(int64_t)counter {
|
|
require(method != nil);
|
|
require(location != nil);
|
|
require(password != nil);
|
|
|
|
NSMutableDictionary* headers = [NSMutableDictionary dictionary];
|
|
if (optionalBody != nil) {
|
|
headers[@"Content-Length"] = [@(optionalBody.length) stringValue];
|
|
}
|
|
headers[@"Authorization"] = [HttpRequest computeOtpAuthorizationTokenForLocalNumber:localNumber andCounterValue:counter andPassword:password];
|
|
|
|
HttpRequest* s = [HttpRequest new];
|
|
s->_method = method;
|
|
s->_location = location;
|
|
s->_optionalBody = optionalBody;
|
|
s->_headers = headers;
|
|
return s;
|
|
}
|
|
|
|
+(HttpRequest*) httpRequestFromData:(NSData*)data {
|
|
require(data != nil);
|
|
NSUInteger requestSize;
|
|
HttpRequestOrResponse* http = [HttpRequestOrResponse tryExtractFromPartialData:data usedLengthOut:&requestSize];
|
|
checkOperation(http.isRequest && requestSize == data.length);
|
|
return [http request];
|
|
}
|
|
|
|
+(NSString*) computeOtpAuthorizationTokenForLocalNumber:(PhoneNumber*)localNumber
|
|
andCounterValue:(int64_t)counterValue
|
|
andPassword:(NSString*)password {
|
|
require(localNumber != nil);
|
|
require(password != nil);
|
|
|
|
NSString* rawToken = [NSString stringWithFormat:@"%@:%@:%lld",
|
|
localNumber.toE164,
|
|
[CryptoTools computeOtpWithPassword:password andCounter:counterValue],
|
|
counterValue];
|
|
return [@"OTP " stringByAppendingString:rawToken.encodedAsUtf8.encodedAsBase64];
|
|
}
|
|
+(NSString*) computeBasicAuthorizationTokenForLocalNumber:(PhoneNumber*)localNumber andPassword:(NSString*)password {
|
|
NSString* rawToken = [NSString stringWithFormat:@"%@:%@",
|
|
localNumber.toE164,
|
|
password];
|
|
return [@"Basic " stringByAppendingString:rawToken.encodedAsUtf8.encodedAsBase64];
|
|
}
|
|
|
|
-(NSString*) toHttp {
|
|
NSMutableArray* r = [NSMutableArray array];
|
|
|
|
[r addObject:self.method];
|
|
[r addObject:@" "];
|
|
[r addObject:self.location];
|
|
[r addObject:@" HTTP/1.0\r\n"];
|
|
|
|
for (NSString* key in self.headers) {
|
|
[r addObject:key];
|
|
[r addObject:@": "];
|
|
[r addObject:(self.headers)[key]];
|
|
[r addObject:@"\r\n"];
|
|
}
|
|
|
|
[r addObject:@"\r\n"];
|
|
if (self.optionalBody != nil) [r addObject:self.optionalBody];
|
|
|
|
return [r componentsJoinedByString:@""];
|
|
}
|
|
-(NSData*) serialize {
|
|
return self.toHttp.encodedAsUtf8;
|
|
}
|
|
-(bool) isEqualToHttpRequest:(HttpRequest *)other {
|
|
return [self.toHttp isEqualToString:other.toHttp]
|
|
&& [self.method isEqualToString:other.method]
|
|
&& [self.location isEqualToString:other.location]
|
|
&& (self.optionalBody == other.optionalBody || [self.optionalBody isEqualToString:[other optionalBody]])
|
|
&& [self.headers isEqualToDictionary:other.headers];
|
|
}
|
|
|
|
-(NSString*) description {
|
|
return [NSString stringWithFormat:@"%@ %@%@",
|
|
self.method,
|
|
self.location,
|
|
self.optionalBody == nil ? @""
|
|
: self.optionalBody.length == 0 ? @" [empty body]"
|
|
: @" [...body...]"];
|
|
}
|
|
|
|
|
|
@end
|