(config, onion, progress, version, auth=None, await_all_uploads=None)
Internal Helper.

    This uses ADD_ONION to add the given service to Tor. The Deferred
    this returns will callback when the ADD_ONION call has succeed,
    *and* when at least one descriptor has been uploaded to a Hidden
    Service Directory.

    :param config: a TorConfig instance

    :param onion: an EphemeralOnionService instance

    :param progress: a callable taking 3 arguments (percent, tag,
        description) that is called some number of times to tell you of
        progress.

    :param version: 2 or 3, which kind of service to create

    :param auth: if not None, create an authenticated service ("basic"
        is the only kind supported currently so a AuthBasic instance
        should be passed)
Internal Helper.
Internal Helper .
def _add_ephemeral_service(config, onion, progress, version, auth=None, await_all_uploads=None):
    """
    Internal Helper.

    This uses ADD_ONION to add the given service to Tor. The Deferred
    this returns will callback when the ADD_ONION call has succeed,
    *and* when at least one descriptor has been uploaded to a Hidden
    Service Directory.

    :param config: a TorConfig instance

    :param onion: an EphemeralOnionService instance

    :param progress: a callable taking 3 arguments (percent, tag,
        description) that is called some number of times to tell you of
        progress.

    :param version: 2 or 3, which kind of service to create

    :param auth: if not None, create an authenticated service ("basic"
        is the only kind supported currently so a AuthBasic instance
        should be passed)
    """
    if onion not in config.EphemeralOnionServices:
        config.EphemeralOnionServices.append(onion)

    # we have to keep this as a Deferred for now so that HS_DESC
    # listener gets added before we issue ADD_ONION
    assert version in (2, 3)
    uploaded_d = _await_descriptor_upload(config.tor_protocol, onion, progress, await_all_uploads)

    # we allow a key to be passed that *doestn'* start with
    # "RSA1024:" because having to escape the ":" for endpoint
    # string syntax (which uses ":" as delimeters) is annoying
    # XXX rethink ^^? what do we do when the type is upgraded?
    # maybe just a magic-character that's different from ":", or
    # force people to escape them?
    if onion.private_key:
        if onion.private_key is not DISCARD and ':' not in onion.private_key:
            if version == 2:
                if not onion.private_key.startswith("RSA1024:"):
                    onion._private_key = "RSA1024:" + onion.private_key
            elif version == 3:
                if not onion.private_key.startswith("ED25519-V3:"):
                    onion._private_key = "ED25519-V3:" + onion.private_key

    # okay, we're set up to listen, and now we issue the ADD_ONION
    # command. this will set ._hostname and ._private_key properly
    keystring = 'NEW:BEST'
    if onion.private_key not in (None, DISCARD):
        keystring = onion.private_key
    elif version == 3:
        keystring = 'NEW:ED25519-V3'
    if version == 3:
        if 'V3' not in keystring:
            raise ValueError(
                "version=3 but private key isn't 'ED25519-V3'"
            )

    # hmm, is it better to validate keyblob args in the create
    # methods? "Feels nicer" to see it here when building ADD_ONION
    # though?
    if '\r' in keystring or '\n' in keystring:
        raise ValueError(
            "No newline or return characters allowed in key blobs"
        )

    cmd = 'ADD_ONION {}'.format(keystring)
    for port in onion._ports:
        cmd += ' Port={},{}'.format(*port.split(' ', 1))
    flags = []
    if onion._detach:
        flags.append('Detach')
    if onion.private_key is DISCARD:
        flags.append('DiscardPK')
    if auth is not None:
        assert isinstance(auth, AuthBasic)  # don't support AuthStealth yet
        if isinstance(auth, AuthBasic):
            flags.append('BasicAuth')
    if onion._single_hop:
        flags.append('NonAnonymous')  # depends on some Tor options, too
    if flags:
        cmd += ' Flags={}'.format(','.join(flags))

    if auth is not None:
        for client_name in auth.client_names():
            keyblob = auth.keyblob_for(client_name)
            if keyblob is None:
                cmd += ' ClientAuth={}'.format(client_name)
            else:
                cmd += ' ClientAuth={}:{}'.format(client_name, keyblob)
                onion._add_client(client_name, keyblob)

    raw_res = yield config.tor_protocol.queue_command(cmd)
    res = find_keywords(raw_res.split('\n'))
    try:
        onion._hostname = res['ServiceID'] + '.onion'
        if onion.private_key is DISCARD:
            onion._private_key = None
        else:
            # if we specified a private key, it's not echoed back
            if not onion.private_key:
                onion._private_key = res['PrivateKey'].strip()
    except KeyError:
        raise RuntimeError(
            "Expected ADD_ONION to return ServiceID= and PrivateKey= args."
            "Got: {}".format(res)
        )

    if auth is not None:
        for line in raw_res.split('\n'):
            if line.startswith("ClientAuth="):
                name, blob = line[11:].split(':', 1)
                onion._add_client(name, blob)

    log.msg("{}: waiting for descriptor uploads.".format(onion.hostname))
    yield uploaded_d
def _add_ephemeral_service ( config , onion , progress , version , auth = None , await_all_uploads = None ) : if onion not in config . EphemeralOnionServices : config . EphemeralOnionServices . append ( onion ) # we have to keep this as a Deferred for now so that HS_DESC # listener gets added before we issue ADD_ONION assert version in ( 2 , 3 ) uploaded_d = _await_descriptor_upload ( config . tor_protocol , onion , progress , await_all_uploads ) # we allow a key to be passed that *doestn'* start with # "RSA1024:" because having to escape the ":" for endpoint # string syntax (which uses ":" as delimeters) is annoying # XXX rethink ^^? what do we do when the type is upgraded? # maybe just a magic-character that's different from ":", or # force people to escape them? if onion . private_key : if onion . private_key is not DISCARD and ':' not in onion . private_key : if version == 2 : if not onion . private_key . startswith ( "RSA1024:" ) : onion . _private_key = "RSA1024:" + onion . private_key elif version == 3 : if not onion . private_key . startswith ( "ED25519-V3:" ) : onion . _private_key = "ED25519-V3:" + onion . private_key # okay, we're set up to listen, and now we issue the ADD_ONION # command. this will set ._hostname and ._private_key properly keystring = 'NEW:BEST' if onion . private_key not in ( None , DISCARD ) : keystring = onion . private_key elif version == 3 : keystring = 'NEW:ED25519-V3' if version == 3 : if 'V3' not in keystring : raise ValueError ( "version=3 but private key isn't 'ED25519-V3'" ) # hmm, is it better to validate keyblob args in the create # methods? "Feels nicer" to see it here when building ADD_ONION # though? if '\r' in keystring or '\n' in keystring : raise ValueError ( "No newline or return characters allowed in key blobs" ) cmd = 'ADD_ONION {}' . format ( keystring ) for port in onion . _ports : cmd += ' Port={},{}' . format ( * port . split ( ' ' , 1 ) ) flags = [ ] if onion . _detach : flags . append ( 'Detach' ) if onion . private_key is DISCARD : flags . append ( 'DiscardPK' ) if auth is not None : assert isinstance ( auth , AuthBasic ) # don't support AuthStealth yet if isinstance ( auth , AuthBasic ) : flags . append ( 'BasicAuth' ) if onion . _single_hop : flags . append ( 'NonAnonymous' ) # depends on some Tor options, too if flags : cmd += ' Flags={}' . format ( ',' . join ( flags ) ) if auth is not None : for client_name in auth . client_names ( ) : keyblob = auth . keyblob_for ( client_name ) if keyblob is None : cmd += ' ClientAuth={}' . format ( client_name ) else : cmd += ' ClientAuth={}:{}' . format ( client_name , keyblob ) onion . _add_client ( client_name , keyblob ) raw_res = yield config . tor_protocol . queue_command ( cmd ) res = find_keywords ( raw_res . split ( '\n' ) ) try : onion . _hostname = res [ 'ServiceID' ] + '.onion' if onion . private_key is DISCARD : onion . _private_key = None else : # if we specified a private key, it's not echoed back if not onion . private_key : onion . _private_key = res [ 'PrivateKey' ] . strip ( ) except KeyError : raise RuntimeError ( "Expected ADD_ONION to return ServiceID= and PrivateKey= args." "Got: {}" . format ( res ) ) if auth is not None : for line in raw_res . split ( '\n' ) : if line . startswith ( "ClientAuth=" ) : name , blob = line [ 11 : ] . split ( ':' , 1 ) onion . _add_client ( name , blob ) log . msg ( "{}: waiting for descriptor uploads." . format ( onion . hostname ) ) yield uploaded_d