(Steve Dougherty)
2013-06-07: Add initial WoT support to fn-pull. Add initial WoT support to fn-pull. * Refactor WoT module to allow functions for parsing responses. * WoT not currently supported, but LCWoT is. * See https://bugs.freenetproject.org/view.php?id=5729
diff --git a/infocalypse/__init__.py b/infocalypse/__init__.py --- a/infocalypse/__init__.py +++ b/infocalypse/__init__.py @@ -510,6 +510,43 @@ def infocalypse_pull(ui_, repo, **opts): params['FMSREAD_HASH'] = opts['hash'][0] params['FMSREAD_ONLYTRUSTED'] = bool(opts['onlytrusted']) request_uri = get_uri_from_hash(ui_, repo, params, stored_cfg) + elif opts['wot']: + import wot + truster = stored_cfg.get_wot_identity( + stored_cfg.get_dir_insert_uri(repo.root)) + # TODO: Require repo name, not full path - look it up from the XML. + + # Expecting <id stuff>/reponame.R1/edition + wot_id, repo_path = opts['wot'].split('/', 1) + + nickname_prefix = '' + key_prefix='' + # Could be nick@key, nick, @key + split = wot_id.split('@') + nickname_prefix = split[0] + + if len(split) == 2: + key_prefix = split[1] + + attributes = wot.resolve_identity(ui_, + truster=truster, + nickname_prefix=nickname_prefix, + key_prefix=key_prefix) + if attributes is None: + return + + # Expecting [freenet:]?USK@key/WebOfTrust/edition + request_uri = attributes['RequestURI'] + # See similar note in fn-create: trim off LCWoT URI prefix. + # TODO: Semantically meaningful key classes. + prefix = "freenet:" + if request_uri.startswith(prefix): + request_uri = request_uri[len(prefix):] + + request_uri = request_uri.split('/', 1)[0] + + request_uri = request_uri + '/' + repo_path + else: request_uri = opts['uri'] diff --git a/infocalypse/config.py b/infocalypse/config.py --- a/infocalypse/config.py +++ b/infocalypse/config.py @@ -201,6 +201,13 @@ class Config: """ self.wot_identities[normalize(for_usk_or_id)] = wot_identity + def get_wot_identity(self, for_usk_or_id): + """ + Return the WoT identity associated with the request USK, + or the default if none is set. + """ + return self.wot_identities[normalize(for_usk_or_id)] + # Hmmm... really nescessary? def get_dir_insert_uri(self, repo_dir): """ Return the insert USK for repo_dir or None. """ diff --git a/infocalypse/wot.py b/infocalypse/wot.py --- a/infocalypse/wot.py +++ b/infocalypse/wot.py @@ -51,10 +51,93 @@ def resolve_local_identity(ui, nickname_ ui.warn("No nicknames start with '{0}'.\n".format(nickname_prefix)) return + return read_local_identity(response, id_num) + +def resolve_identity(ui, truster, nickname_prefix=None, key_prefix=''): + """ + If using LCWoT, either the nickname prefix should be enough to be + unambiguous, or failing that enough of the key. + If using WoT, partial search is not supported, and the entire key must be + specified. + + Returns a dictionary of the nickname, request URI, + and identity that matches the given criteria. + In the case of an error prints a message and returns None. + + :param ui: Mercurial ui for error messages. + :param truster: Check trust list of this local identity. + :param nickname_prefix: Partial (prefix) of nickname. Can be whole. + :param key_prefix: Partial (prefix) of key. Can be empty. + """ + # TODO: Support different FCP IP / port. + node = fcp.FCPNode() + + # Test for GetIdentitiesByPartialNickname support. currently LCWoT-only. + # https://github.com/tmarkus/LessCrappyWebOfTrust/blob/master/src/main/java/plugins/WebOfTrust/fcp/GetIdentitiesByPartialNickname.java + params = {'Message': 'GetIdentitiesByPartialNickname', + 'Truster': truster, + 'PartialNickname': nickname_prefix, + 'PartialID': key_prefix, + 'MaxIdentities': 1, # Match must be unambiguous. + 'Context': 'vcs'} + response =\ + node.fcpPluginMessage(async=False, + plugin_name="plugins.WebOfTrust.WebOfTrust", + plugin_params=params)[0] + + if response['header'] != 'FCPPluginReply' or\ + 'Replies.Message' not in response: + ui.warn('Unexpected reply. Got {0}\n'.format(response)) + return + elif response['Replies.Message'] == 'Identities': + return read_identity(response, 0) + elif response['Replies.Message'] == 'Error': + # The difficulty here is that the message type is Error for both an + # unrecognized message type and ambiguous search terms. + # TODO: This seems likely to break - the Description seems intended + # for human readers and will probably change. + if response['Replies.Description'].startswith('Number of matched'): + # Supported version of LCWoT - terms ambiguous. + ui.warn("'{0}@{1}' is ambiguous.".format(nickname_prefix, + key_prefix)) + return + elif response['Replies.Description'].startswith('Unknown message') or\ + response['Replies.Description'].startswith('Could not match'): + # Not supported; check for exact identity. + ui.warn('Searching by partial nickname/key not supported.') + + # Attempt to search failed - check for exact key. Here key_prefix must be + # a complete key for the lookup to succeed. + params = {'Message': 'GetIdentity', + 'Truster': truster, + 'Identity': key_prefix} + response =\ + node.fcpPluginMessage(async=False, + plugin_name="plugins.WebOfTrust.WebOfTrust", + plugin_params=params)[0] + + # There should be only one result. + # Depends on https://bugs.freenetproject.org/view.php?id=5729 + print read_identity(response, 0) + +def read_local_identity(message, id_num): + """ + Reads an FCP response from a WoT plugin describing a local identity and + returns a dictionary of Nickname, InsertURI, RequestURI, and Identity. + """ + result = read_identity(message, id_num) + result['InsertURI'] = message['Replies.InsertURI{0}'.format(id_num)] + return result + +def read_identity(message, id_num): + """ + Reads an FCP response from a WoT plugin describing an identity and + returns a dictionary of Nickname, RequestURI, and Identity. + """ # Return properties for the selected identity. (by number) result = {} - for item in [ 'Nickname', 'InsertURI','RequestURI', 'Identity' ]: - result[item] = response['Replies.{0}{1}'.format(item, id_num)] + for item in [ 'Nickname', 'RequestURI', 'Identity' ]: + result[item] = message['Replies.{0}{1}'.format(item, id_num)] # LCWoT also puts these things as properties, which would be nicer to # depend on and would allow just returning all properties for the identity.