Skip to content
This repository has been archived by the owner on Mar 9, 2022. It is now read-only.

Commit

Permalink
Port, auth, Bonjour config for listener
Browse files Browse the repository at this point in the history
Lots of additions to TDListener:
* Set port to 0 to get a dynamically-assigned port number (access the .port property to find out what it is.)
* Can publish via Bonjour by setting service name/type and optionally TXT dictionary.
* Can require authentication by supplying usernames and passwords.
  • Loading branch information
snej committed May 25, 2012
1 parent b44e545 commit 0235b18
Show file tree
Hide file tree
Showing 4 changed files with 101 additions and 4 deletions.
20 changes: 17 additions & 3 deletions Demo-Mac/TouchServ.m
Expand Up @@ -10,6 +10,7 @@
#import <TouchDB/TouchDB.h>
#import <TouchDB/TDRouter.h>
#import <TouchDBListener/TDListener.h>
#import "CollectionUtils.h"

#if DEBUG
#import "Logging.h"
Expand Down Expand Up @@ -61,15 +62,28 @@ int main (int argc, const char * argv[])
// Start a listener socket:
TDListener* listener = [[TDListener alloc] initWithTDServer: server port: kPortNumber];

if (argc >= 2 && strcmp(argv[1], "--readonly") == 0)
listener.readOnly = YES;
[listener setBonjourName: @"TouchServ" type: @"_touchdb._tcp."];
listener.TXTRecordDictionary = $dict({@"Key",
[@"value" dataUsingEncoding: NSUTF8StringEncoding]});

for (int i = 1; i < argc; ++i) {
if (strcmp(argv[i], "--readonly") == 0) {
listener.readOnly = YES;
} else if (strcmp(argv[i], "--auth") == 0) {
srandomdev();
NSString* password = $sprintf(@"%x", random());
listener.passwords = [NSDictionary dictionaryWithObject: password
forKey: @"touchdb"];
Log(@"Auth required: user='touchdb', password='%@'", password);
}
}

[listener start];

Log(@"TouchServ %@ is listening%@ on port %d ... relax!",
[TDRouter versionString],
(listener.readOnly ? @" in read-only mode" : @""),
kPortNumber);
listener.port);

[[NSRunLoop currentRunLoop] run];

Expand Down
14 changes: 14 additions & 0 deletions Listener/TDHTTPConnection.m
Expand Up @@ -36,6 +36,20 @@ - (TDListener*) listener {
}


- (BOOL)isPasswordProtected:(NSString *)path {
return self.listener.requiresAuth;
}

- (NSString*) realm {
return self.listener.realm;
}

- (NSString*) passwordForUser: (NSString*)username {
LogTo(TDListener, @"Login attempted for user '%@'", username);
return [self.listener passwordForUser: username];
}


- (BOOL)supportsMethod:(NSString *)method atPath:(NSString *)path {
return $equal(method, @"POST") || $equal(method, @"PUT") || $equal(method, @"DELETE")
|| [super supportsMethod: method atPath: path];
Expand Down
40 changes: 40 additions & 0 deletions Listener/TDListener.h
Expand Up @@ -15,14 +15,54 @@
{
TDHTTPServer* _httpServer;
TDServer* _tdServer;
NSString* _realm;
BOOL _readOnly;
BOOL _requiresAuth;
NSDictionary* _passwords;
}

/** Initializes a TDListener.
@param server The TDServer whose databases to serve.
@param port The TCP port number to listen on. Use 0 to automatically pick an available port (you can get the port number after the server starts by getting the .port property.) */
- (id) initWithTDServer: (TDServer*)server port: (UInt16)port;

/** The TCP port number that the listener is listening on.
If the listener has not yet started, this will return 0. */
@property (readonly) UInt16 port;


/** The Bonjour service name and type to advertise as.
@param name The service name; this can be arbitrary but is generally the device user's name. An empty string will be mapped to the device's name.
@param type The service type; the type of a generic HTTP server is "_http._tcp." but you should use something more specific. */
- (void) setBonjourName: (NSString*)name type: (NSString*)type;

/** Bonjour metadata associated with the service. Changes will be visible almost immediately.
The keys are NSStrings and values are NSData. Total size should be kept small (under 1kbyte if possible) as this data is multicast over UDP. */
@property (copy) NSDictionary* TXTRecordDictionary;


/** If set to YES, remote requests will not be allowed to make any changes to the server or its databases. */
@property BOOL readOnly;

/** If set to YES, all requests will be required to authenticate.
Setting a .passwords dictionary automatically enables this.*/
@property BOOL requiresAuth;

/** Security realm string to return in authentication challenges. */
@property (copy) NSString* realm;

/** Sets user names and passwords for authentication.
@param passwords A dictionary mapping user names to passwords. */
- (void) setPasswords: (NSDictionary*)passwords;

/** Returns the password assigned to a user name, or nil if the name is not recognized. */
- (NSString*) passwordForUser: (NSString*)username;


/** Starts the listener. */
- (BOOL) start;

/** Stops the listener. */
- (void) stop;

@end
31 changes: 30 additions & 1 deletion Listener/TDListener.m
Expand Up @@ -24,7 +24,7 @@
@implementation TDListener


@synthesize readOnly=_readOnly;
@synthesize readOnly=_readOnly, requiresAuth=_requiresAuth, realm=_realm;


- (id) initWithTDServer: (TDServer*)server port: (UInt16)port {
Expand All @@ -36,6 +36,7 @@ - (id) initWithTDServer: (TDServer*)server port: (UInt16)port {
_httpServer.tdServer = _tdServer;
_httpServer.port = port;
_httpServer.connectionClass = [TDHTTPConnection class];
self.realm = @"TouchDB";
}
return self;
}
Expand All @@ -46,10 +47,22 @@ - (void)dealloc
[self stop];
[_tdServer release];
[_httpServer release];
[_realm release];
[_passwords release];
[super dealloc];
}


- (void) setBonjourName: (NSString*)name type: (NSString*)type {
_httpServer.name = name;
_httpServer.type = type;
}

- (NSDictionary *)TXTRecordDictionary {return _httpServer.TXTRecordDictionary;}
- (void)setTXTRecordDictionary:(NSDictionary *)dict {_httpServer.TXTRecordDictionary = dict;}



- (BOOL) start {
NSError* error;
return [_httpServer start: &error];
Expand All @@ -60,6 +73,22 @@ - (void) stop {
}


- (UInt16) port {
return _httpServer.listeningPort;
}


- (void) setPasswords: (NSDictionary*)passwords {
[_passwords autorelease];
_passwords = [passwords copy];
_requiresAuth = (_passwords != nil);
}

- (NSString*) passwordForUser:(NSString *)username {
return [_passwords objectForKey: username];
}


@end


Expand Down

0 comments on commit 0235b18

Please sign in to comment.