Ejemplo n.º 1
0
 def test_parser(self):
     """
     ``AcmeParser`` creates an endpoint with the specified ACME directory
     and directory store.
     """
     directory = URL.fromText(u'https://example.com/acme')
     parser = _AcmeParser(u'prefix', directory)
     tempdir = self.useFixture(TempDir()).path
     temp_path = FilePath(tempdir)
     key_path = temp_path.child('client.key')
     reactor = object()
     self.assertThat(
         parser.parseStreamServer(reactor, tempdir, 'tcp', '443'),
         MatchesAll(
             IsInstance(AutoTLSEndpoint),
             MatchesStructure(
                 reactor=Is(reactor),
                 directory=Equals(directory),
                 cert_store=MatchesAll(
                     IsInstance(DirectoryStore),
                     MatchesStructure(
                         path=Equals(temp_path))),
                 cert_mapping=MatchesAll(
                     IsInstance(HostDirectoryMap),
                     MatchesStructure(
                         directoryPath=Equals(temp_path))),
                 sub_endpoint=MatchesPredicate(
                     IStreamServerEndpoint.providedBy,
                     '%r is not a stream server endpoint'))))
     self.assertThat(key_path.isfile(), Equals(True))
     key_data = key_path.getContent()
     parser.parseStreamServer(reactor, tempdir, 'tcp', '443'),
     self.assertThat(key_path.getContent(), Equals(key_data))
 def _parse_fluentd_http(self, kind, args):
     return lambda reactor: FluentdDestination(
         # Construct the pool ourselves with the default of using
         # persistent connections to override Agent's default of not using
         # persistent connections.
         agent=Agent(reactor, pool=HTTPConnectionPool(reactor)),
         fluentd_url=URL.fromText(args),
     )
Ejemplo n.º 3
0
 def _reconstitute(self):
     """
     Reconstitute this L{URLPath} from all its given attributes.
     """
     urltext = urlquote(
         urlparse.urlunsplit((self._scheme, self._netloc, self._path, self._query, self._fragment)), safe=_allascii
     )
     self._url = _URL.fromText(urltext.encode("ascii").decode("ascii"))
 def get_kubernetes_service(self, reactor):
     if self["k8s-service-account"]:
         return network_kubernetes(
             # XXX is this really the url to use?
             base_url=URL.fromText(self["kubernetes"].decode("ascii")),
             agent=authenticate_with_serviceaccount(reactor),
         )
     return network_kubernetes_from_context(reactor, self["k8s-context"], self["k8s-config"])
 def from_service_account(cls):
     from twisted.internet import reactor
     kubernetes = network_kubernetes(
         base_url=URL.fromText(u"https://kubernetes/"),
         agent=authenticate_with_serviceaccount(reactor),
     )
     client = kubernetes.client()
     return cls(k8s=client)
 def _url(self, *segments, **query):
     url = URL.fromText(
         self.endpoint.decode("utf-8"),
     ).child(*segments)
     for k, v in query.items():
         url = url.add(
             k.decode("utf-8"),
             quote(v.encode("utf-8"), safe="").decode("ascii"),
         )
     return url.asURI().asText().encode("ascii")
Ejemplo n.º 7
0
 def gotRTM(response):
     url = URL.fromText(response[u'url'])
     if url.scheme != u'wss':
         raise RuntimeError(url)
     factory.setSessionParameters(
         response[u'url'], useragent=factory.useragent)
     self.me = response[u'self']
     self.users = {u[u'id']: u for u in response[u'users']}
     self.channels = {c[u'id']: c for c in response[u'channels']}
     self.ims = {im[u'id']: im for im in response[u'ims']}
     print factory
     return self._makeEndpoint(url).connect(factory)
Ejemplo n.º 8
0
 def setUp(self):
     super(EndpointTests, self).setUp()
     clock = Clock()
     clock.rightNow = (
         datetime.now() - datetime(1970, 1, 1)).total_seconds()
     client = FakeClient(RSA_KEY_512, clock)
     self.endpoint = AutoTLSEndpoint(
         reactor=clock,
         directory=URL.fromText(u'https://example.com/'),
         client_creator=lambda reactor, directory: succeed(client),
         cert_store=MemoryStore(),
         cert_mapping={},
         sub_endpoint=DummyEndpoint())
Ejemplo n.º 9
0
def create_session(endpoint, request=treq.request):
    """
    Create a new `Session` instance.

    :param unicode endpoint: URI to the root of the Documint service.
    :param request: Callable for making requests.
    :type request: Callable mimicing the signature of `treq.request`.
    """
    uri = URL.fromText(endpoint).child(u'sessions').child(u'')
    request = documint_request_factory(request)
    d = post_json(request, uri.asURI().asText().encode('utf-8'))
    d.addCallback(itemgetter(u'links'))
    d.addCallback(Session, request)
    return d
 def _make_wormhole_claim(self, customer_email, customer_id, subscription_id, old_secrets):
     plan_identifier = u"foobar"
     reactor = Clock()
     provisioner = get_provisioner(
         reactor,
         URL.fromText(u"http://subscription-manager/"),
         partial(self._provision_subscription, old_secrets),
     )
     server = MemoryWormholeServer()
     signup = get_wormhole_signup(
         reactor,
         provisioner,
         server,
         URL.fromText(u"ws://foo.invalid/"),
         FilePath(self.mktemp()),
     )
     d = signup.signup(
         customer_email,
         customer_id,
         subscription_id,
         plan_identifier,
     )
     return self.successResultOf(d)
Ejemplo n.º 11
0
def _addSlash(request):
    """
    Add a trailing slash to C{request}'s URI.

    @param request: The incoming request to add the ending slash to.
    @type request: An object conforming to L{twisted.web.iweb.IRequest}

    @return: A URI with a trailing slash, with query and fragment preserved.
    @rtype: L{bytes}
    """
    url = URL.fromText(request.uri.decode('ascii'))
    # Add an empty path segment at the end, so that it adds a trailing slash
    url = url.replace(path=list(url.path) + [u""])
    return url.asText().encode('ascii')
Ejemplo n.º 12
0
def _addSlash(request):
    """
    Add a trailing slash to C{request}'s URI.

    @param request: The incoming request to add the ending slash to.
    @type request: An object conforming to L{twisted.web.iweb.IRequest}

    @return: A URI with a trailing slash, with query and fragment preserved.
    @rtype: L{bytes}
    """
    url = URL.fromText(request.uri.decode('ascii'))
    # Add an empty path segment at the end, so that it adds a trailing slash
    url = url.replace(path=list(url.path) + [u""])
    return url.asText().encode('ascii')
Ejemplo n.º 13
0
 def __init__(self,
              scheme=b'',
              netloc=b'localhost',
              path=b'',
              query=b'',
              fragment=b''):
     self.scheme = scheme or b'http'
     self.netloc = netloc
     self.path = path or b'/'
     self.query = query
     self.fragment = fragment
     urltext = urlquote(urlparse.urlunsplit(
         (self.scheme, self.netloc, self.path, self.query, self.fragment)),
                        safe=_allascii)
     self._url = _URL.fromText(urltext.encode("ascii").decode("ascii"))
Ejemplo n.º 14
0
def authenticate_with_serviceaccount(reactor, **kw):
    """
    Create an ``IAgent`` which can issue authenticated requests to a
    particular Kubernetes server using a service account token.

    :param reactor: The reactor with which to configure the resulting agent.

    :param bytes path: The location of the service account directory.  The
        default should work fine for normal use within a container.

    :return IAgent: An agent which will authenticate itself to a particular
        Kubernetes server and which will verify that server or refuse to
        interact with it.
    """
    config = KubeConfig.from_service_account(**kw)

    token = config.user["token"]
    base_url = URL.fromText(config.cluster["server"].decode("ascii"))

    ca_certs = pem.parse(config.cluster["certificate-authority"].bytes())
    if not ca_certs:
        raise ValueError("No certificate authority certificate found.")
    ca_cert = ca_certs[0]

    try:
        # Validate the certificate so we have early failures for garbage data.
        ssl.Certificate.load(ca_cert.as_bytes(), FILETYPE_PEM)
    except OpenSSLError as e:
        raise ValueError(
            "Invalid certificate authority certificate found.",
            str(e),
        )

    netloc = NetLocation(host=base_url.host, port=base_url.port)
    policy = ClientCertificatePolicyForHTTPS(
        credentials={},
        trust_roots={
            netloc: ca_cert,
        },
    )

    agent = HeaderInjectingAgent(
        _to_inject=Headers({u"authorization": [u"Bearer {}".format(token)]}),
        _agent=Agent(reactor, contextFactory=policy),
    )
    return agent
Ejemplo n.º 15
0
def create_marathon_acme(
    storage_dir, acme_directory, acme_email, allow_multiple_certs,
    marathon_addrs, marathon_timeout, sse_timeout, mlb_addrs, group,
        reactor):
    """
    Create a marathon-acme instance.

    :param storage_dir:
        Path to the storage directory for certificates and the client key.
    :param acme_directory: Address for the ACME directory to use.
    :param acme_email:
        Email address to use when registering with the ACME service.
    :param allow_multiple_certs:
        Whether to allow multiple certificates per app port.
    :param marathon_addr:
        Address for the Marathon instance to find app domains that require
        certificates.
    :param marathon_timeout:
        Amount of time in seconds to wait for response headers to be received
        from Marathon.
    :param sse_timeout:
        Amount of time in seconds to wait for some event data to be received
        from Marathon.
    :param mlb_addrs:
        List of addresses for marathon-lb instances to reload when a new
        certificate is issued.
    :param group:
        The marathon-lb group (``HAPROXY_GROUP``) to consider when finding
        app domains.
    :param reactor: The reactor to use.
    """
    storage_path, certs_path = init_storage_dir(storage_dir)
    acme_url = URL.fromText(_to_unicode(acme_directory))
    key = maybe_key(storage_path)

    return MarathonAcme(
        MarathonClient(marathon_addrs, timeout=marathon_timeout,
                       sse_kwargs={'timeout': sse_timeout}, reactor=reactor),
        group,
        DirectoryStore(certs_path),
        MarathonLbClient(mlb_addrs, reactor=reactor),
        create_txacme_client_creator(reactor, acme_url, key),
        reactor,
        acme_email,
        allow_multiple_certs)
Ejemplo n.º 16
0
    def fromString(klass, url):
        """
        Make a L{URLPath} from a L{str} or L{unicode}.

        @param url: A L{str} representation of a URL.
        @type url: L{str} or L{unicode}.

        @return: a new L{URLPath} derived from the given string.
        @rtype: L{URLPath}
        """
        if not isinstance(url, (str, unicode)):
            raise ValueError("'url' must be a str or unicode")
        if isinstance(url, bytes):
            # On Python 2, accepting 'str' (for compatibility) means we might
            # get 'bytes'.  On py3, this will not work with bytes due to the
            # check above.
            return klass.fromBytes(url)
        return klass._fromURL(_URL.fromText(url))
Ejemplo n.º 17
0
    def fromString(klass, url):
        """
        Make a L{URLPath} from a L{str} or L{unicode}.

        @param url: A L{str} representation of a URL.
        @type url: L{str} or L{unicode}.

        @return: a new L{URLPath} derived from the given string.
        @rtype: L{URLPath}
        """
        if not isinstance(url, (str, unicode)):
            raise ValueError("'url' must be a str or unicode")
        if isinstance(url, bytes):
            # On Python 2, accepting 'str' (for compatibility) means we might
            # get 'bytes'.  On py3, this will not work with bytes due to the
            # check above.
            return klass.fromBytes(url)
        return klass._fromURL(_URL.fromText(url))
Ejemplo n.º 18
0
    def setUp(self):
        super(TestSignupModule, self).setUp()
        self.mockconfigdir = FilePath('./test_signup').child('TestSignupModule')
        make_dirs(self.mockconfigdir.path)
        self.SIGNUPSPATH = 'mock_signups.csv'
        self.CONFIGFILEPATH = 'init_test_config.json'
        self.EC2SECRETPATH = 'mock_ec2_secret'
        self.S3SECRETPATH = 'mock_s3_secret'
        self.MONITORPUBKEYPATH = 'MONITORKEYS.pub'

        self.MEMAIL = 'MEMAIL'
        self.MKEYINFO = 'MKEYINFO'
        self.MCUSTOMER_ID = u'cus_x14Charactersx'
        self.MSUBSCRIPTION_ID = u'sub_x14Characterx'
        self.MPLAN_ID = 'XX_consumer_iteration_#_GREEKLETTER#_2XXX-XX-XX'
        self.MENCODED_IDS = 'on2wex3yge2eg2dbojqwg5dfoj4a-mn2xgx3yge2eg2dbojqwg5dfojzxq'

        FilePath(self.SIGNUPSPATH).setContent('')
        FilePath(self.CONFIGFILEPATH).setContent(CONFIGFILEJSON)
        FilePath(self.EC2SECRETPATH).setContent(MOCKEC2SECRETCONTENTS)
        FilePath(self.S3SECRETPATH).setContent(MOCKS3SECRETCONTENTS)
        FilePath(self.MONITORPUBKEYPATH).setContent(MONITORPUBKEY)

        self.DEPLOYMENT_CONFIGURATION = model.DeploymentConfiguration(
            domain=u"s4.example.com",
            kubernetes_namespace=u"testing",
            subscription_manager_endpoint=URL.fromText(u"http://localhost/"),
            s3_access_key_id=ZEROPRODUCT["s3_access_key_id"],
            s3_secret_key=MOCKS3SECRETCONTENTS,

            introducer_image=u"tahoe-introducer",
            storageserver_image=u"tahoe-storageserver",
        )
        self.SUBSCRIPTION = model.SubscriptionDetails(
            bucketname="lae-" + self.MENCODED_IDS,
            oldsecrets=old_secrets().example(),
            customer_email=self.MEMAIL,
            customer_pgpinfo=self.MKEYINFO,
            product_id=u"filler",
            customer_id=self.MCUSTOMER_ID,
            subscription_id=self.MSUBSCRIPTION_ID,
            introducer_port_number=12345,
            storage_port_number=12346,
        )
Ejemplo n.º 19
0
def get_things_done():
    """
    Here is where the service part is setup and action is done.
    """
    responders = yield start_responders()

    store = MemoryStore()

    # We first validate the directory.
    account_key = _get_account_key()
    try:
        client = yield Client.from_url(
            reactor,
            URL.fromText(acme_url.decode('utf-8')),
            key=JWKRSA(key=account_key),
            alg=RS256,
        )
    except Exception as error:
        print('\n\nFailed to connect to ACME directory. %s' % (error, ))
        yield reactor.stop()
        defer.returnValue(None)

    service = AcmeIssuingService(
        email='[email protected],[email protected]',
        cert_store=store,
        client=client,
        clock=reactor,
        responders=responders,
        panic=on_panic,
    )

    # Start the service and wait for it to start.
    yield service.start()

    # Wait for the existing certificate from the storage to be available.
    yield service.when_certs_valid()

    # Request a SAN ... if passed via command line.
    yield service.issue_cert(','.join(requested_domains))

    yield service.stopService()

    print('That was all the example.')
Ejemplo n.º 20
0
def _finish_convergence_service(k8s_client, options, subscription_client):
    k8s = KubeClient(k8s=k8s_client)

    access_key_id = FilePath(
        options["aws-access-key-id-path"]).getContent().strip()
    secret_access_key = FilePath(
        options["aws-secret-access-key-path"]).getContent().strip()

    aws = AWSServiceRegion(creds=AWSCredentials(
        access_key=access_key_id,
        secret_key=secret_access_key,
    ))

    Message.log(
        event=u"convergence-service:key-notification",
        key_id=access_key_id.decode("ascii"),
        secret_key_hash=sha256(secret_access_key).hexdigest().decode("ascii"),
    )

    # XXX I get to leave a ton of fields empty because I happen to know
    # they're not used in this codepath. :/ Maybe this suggests something has
    # gone wrong ...
    config = DeploymentConfiguration(
        domain=options["domain"].decode("ascii"),
        kubernetes_namespace=options["kubernetes-namespace"].decode("ascii"),
        subscription_manager_endpoint=URL.fromText(
            options["endpoint"].decode("ascii")),
        s3_access_key_id=access_key_id.decode("ascii"),
        s3_secret_key=secret_access_key.decode("ascii"),
        introducer_image=options["introducer-image"].decode("ascii"),
        storageserver_image=options["storageserver-image"].decode("ascii"),
        log_gatherer_furl=None,
        stats_gatherer_furl=None,
    )

    return TimerService(
        options["interval"],
        divert_errors_to_log(converge, u"subscription_converger"),
        config,
        subscription_client,
        k8s,
        aws,
    )
def _finish_convergence_service(
    k8s_client, options, subscription_client, reactor,
):
    k8s = KubeClient(k8s=k8s_client)

    access_key_id = FilePath(options["aws-access-key-id-path"]).getContent().strip()
    secret_access_key = FilePath(options["aws-secret-access-key-path"]).getContent().strip()

    aws = AWSServiceRegion(creds=AWSCredentials(
        access_key=access_key_id,
        secret_key=secret_access_key,
    ))

    Message.log(
        event=u"convergence-service:key-notification",
        key_id=access_key_id.decode("ascii"),
        secret_key_hash=sha256(secret_access_key).hexdigest().decode("ascii"),
    )

    config = DeploymentConfiguration(
        domain=options["domain"].decode("ascii"),
        kubernetes_namespace=options["kubernetes-namespace"].decode("ascii"),
        subscription_manager_endpoint=URL.fromText(options["endpoint"].decode("ascii")),

        s3_access_key_id=access_key_id.decode("ascii"),
        s3_secret_key=secret_access_key.decode("ascii"),

        introducer_image=options["introducer-image"].decode("ascii"),
        storageserver_image=options["storageserver-image"].decode("ascii"),

        log_gatherer_furl=options["log-gatherer-furl"],
        stats_gatherer_furl=options["stats-gatherer-furl"],
    )

    return _convergence_service(
        reactor,
        options["interval"],
        config,
        subscription_client,
        k8s,
        aws,
    )
def _finish_convergence_service(
    k8s_client, options, subscription_client, reactor,
):
    k8s = KubeClient(k8s=k8s_client)

    access_key_id = FilePath(options["aws-access-key-id-path"]).getContent().strip()
    secret_access_key = FilePath(options["aws-secret-access-key-path"]).getContent().strip()

    aws = AWSServiceRegion(creds=AWSCredentials(
        access_key=access_key_id,
        secret_key=secret_access_key,
    ))

    Message.log(
        event=u"convergence-service:key-notification",
        key_id=access_key_id.decode("ascii"),
        secret_key_hash=sha256(secret_access_key).hexdigest().decode("ascii"),
    )

    config = DeploymentConfiguration(
        domain=options["domain"].decode("ascii"),
        kubernetes_namespace=options["kubernetes-namespace"].decode("ascii"),
        subscription_manager_endpoint=URL.fromText(options["endpoint"].decode("ascii")),

        s3_access_key_id=access_key_id.decode("ascii"),
        s3_secret_key=secret_access_key.decode("ascii"),

        introducer_image=options["introducer-image"].decode("ascii"),
        storageserver_image=options["storageserver-image"].decode("ascii"),

        log_gatherer_furl=options["log-gatherer-furl"],
        stats_gatherer_furl=options["stats-gatherer-furl"],
    )

    return _convergence_service(
        reactor,
        options["interval"],
        config,
        subscription_client,
        k8s,
        aws,
    )
Ejemplo n.º 23
0
def network_kubernetes_from_context(reactor, context, path=None):
    """
    Create a new ``IKubernetes`` provider based on a kube config file.

    :param reactor: A Twisted reactor which will be used for I/O and
        scheduling.

    :param unicode context: The name of the kube config context from which to
        load configuration details.

    :param FilePath path: The location of the kube config file to use.

    :return IKubernetes: The Kubernetes service described by the named
        context.
    """
    if path is None:
        path = FilePath(expanduser(u"~/.kube/config"))

    config = KubeConfig.from_file(path.path)
    context = config.contexts[context]
    cluster = config.clusters[context[u"cluster"]]
    user = config.users[context[u"user"]]

    base_url = URL.fromText(cluster[u"server"].decode("ascii"))
    [ca_cert] = parse(cluster[u"certificate-authority"].bytes())

    client_chain = parse(user[u"client-certificate"].bytes())
    [client_key] = parse(user[u"client-key"].bytes())

    agent = authenticate_with_certificate_chain(
        reactor,
        base_url,
        client_chain,
        client_key,
        ca_cert,
    )

    return network_kubernetes(
        base_url=base_url,
        agent=agent,
    )
Ejemplo n.º 24
0
    def __init__(self, perfmon, server_name, server_address, server_port, username, password, verify, included_objects):
        self.perfmon = perfmon
        self.server_name = server_name
        self.server_address = server_address
        self.server_port = server_port
        self.username = username
        self.password = password
        self.verify = verify
        self.included_objects = included_objects

        self.authorization = base64.b64encode('{}:{}'.format(self.username, self.password).encode('utf-8'))
        self.headers = Headers({b'Content-Type': [b'text/xml; charset=utf-8'],
                                b'Authorization': [b'Basic ' + self.authorization]})

        self.agent = RateLimitAgent()
        if not self.verify:
            self.agent.contextFactory.good_domains.append(self.server_address.encode('utf-8'))

        self.url = URL.fromText('https://{server_address:}:{server_port:}/perfmonservice2/services/PerfmonService?wsdl'.format(server_address=server_address,
                                                                                                                               server_port=server_port))

        self.openSession()
Ejemplo n.º 25
0
    def test_parser(self):
        """
        ``AcmeParser`` creates an endpoint with the specified ACME directory
        and directory store.
        """
        directory = URL.fromText(u'https://example.com/acme')
        parser = _AcmeParser(u'prefix', directory)
        tempdir = self.useFixture(TempDir()).path
        temp_path = FilePath(tempdir)
        key_path = temp_path.child('client.key')
        reactor = MemoryReactorClock()
        self.assertThat(
            parser.parseStreamServer(reactor, tempdir, 'tcp', '443',
                                     timeout=0),
            MatchesAll(
                IsInstance(AutoTLSEndpoint),
                MatchesStructure(
                    reactor=Is(reactor),
                    directory=Equals(directory),
                    cert_store=MatchesAll(
                        IsInstance(DirectoryStore),
                        MatchesStructure(path=Equals(temp_path))),
                    cert_mapping=MatchesAll(
                        IsInstance(HostDirectoryMap),
                        MatchesStructure(directoryPath=Equals(temp_path))),
                    sub_endpoint=MatchesPredicate(
                        IStreamServerEndpoint.providedBy,
                        '%r is not a stream server endpoint'))))
        self.assertThat(key_path.isfile(), Equals(True))
        key_data = key_path.getContent()

        # Multiple instances with certificates from the same local directory,
        # will serve the same certificates.
        parser.parseStreamServer(reactor, tempdir, 'tcp', '443', timeout=0)
        self.assertThat(key_path.getContent(), Equals(key_data))

        # Check that reactor is clean.
        self.assertEquals(0, len(reactor.getDelayedCalls()))
Ejemplo n.º 26
0
def https_policy_from_config(config):
    """
    Create an ``IPolicyForHTTPS`` which can authenticate a Kubernetes API
    server.

    :param KubeConfig config: A Kubernetes configuration containing an active
        context identifying a cluster.  The resulting ``IPolicyForHTTPS`` will
        authenticate the API server for that cluster.

    :return IPolicyForHTTPS: A TLS context which requires server certificates
        signed by the certificate authority certificate associated with the
        active context's cluster.
    """
    server = config.cluster["server"]
    base_url = URL.fromText(native_string_to_unicode(server))

    ca_certs = pem.parse(config.cluster["certificate-authority"].bytes())
    if not ca_certs:
        raise ValueError("No certificate authority certificate found.")
    ca_cert = ca_certs[0]

    try:
        # Validate the certificate so we have early failures for garbage data.
        ssl.Certificate.load(ca_cert.as_bytes(), FILETYPE_PEM)
    except OpenSSLError as e:
        raise ValueError(
            "Invalid certificate authority certificate found.",
            str(e),
        )

    netloc = NetLocation(host=base_url.host, port=base_url.port)
    policy = ClientCertificatePolicyForHTTPS(
        credentials={},
        trust_roots={
            netloc: ca_cert,
        },
    )
    return policy
Ejemplo n.º 27
0
 def requestRedirectError(self, request, failure):
     """
     Redirect.
     """
     url = URL.fromText(failure.value.args[0].decode("utf-8"))
     return self.redirect(request, url)
Ejemplo n.º 28
0
class URLs(object):
    """
    Incident Management System URL schema.
    """

    root = URL.fromText(u"/")

    prefix = URL.fromText(u"/ims/")

    styleSheet = prefix.child(u"style.css")

    logo = prefix.child(u"logo.png")

    login = prefix.child(u"login")
    logout = prefix.child(u"logout")

    jqueryBase = prefix.child(u"jquery").child(u"")
    jqueryJS = jqueryBase.child(u"jquery.min.js")
    jqueryMap = jqueryBase.child(u"jquery.min.map")

    bootstrapBase = prefix.child(u"bootstrap").child(u"")
    bootstrapCSS = bootstrapBase.child(u"css", u"bootstrap.min.css")
    bootstrapJS = bootstrapBase.child(u"js", u"bootstrap.min.js")

    dataTablesBase = prefix.child(u"datatables").child(u"")
    dataTablesJS = dataTablesBase.child(u"media", u"js",
                                        u"jquery.dataTables.min.js")
    dataTablesbootstrapCSS = dataTablesBase.child(
        u"media", u"css", u"dataTables.bootstrap.min.css")
    dataTablesbootstrapJS = dataTablesBase.child(
        u"media", u"js", u"dataTables.bootstrap.min.js")

    momentJS = prefix.child(u"moment.min.js")

    lscacheJS = prefix.child(u"lscache.min.js")

    # API endpoints
    api = prefix.child(u"api").child(u"")
    ping = api.child(u"ping").child(u"")
    acl = api.child(u"access")
    streets = api.child(u"streets")
    personnel = api.child(u"personnel").child(u"")
    incidentTypes = api.child(u"incident_types").child(u"")
    incidentReports = api.child(u"incident_reports").child(u"")
    incidentReport = incidentReports.child(u"<number>")
    events = api.child(u"events").child(u"")
    event = events.child(u"<eventID>").child(u"")
    locations = event.child(u"locations").child(u"")
    incidents = event.child(u"incidents").child(u"")
    incidentNumber = incidents.child(u"<number>")

    eventSource = api.child(u"eventsource")

    # Web UI
    imsJS = prefix.child(u"ims.js")

    admin = prefix.child(u"admin").child(u"")
    adminJS = admin.child(u"admin.js")

    adminAccessControl = admin.child(u"access")
    adminAccessControlJS = admin.child(u"access.js")

    adminIncidentTypes = admin.child(u"types")
    adminIncidentTypesJS = admin.child(u"types.js")

    adminStreets = admin.child(u"streets")
    adminStreetsJS = admin.child(u"streets.js")

    viewEvents = prefix.child(u"events").child(u"")
    viewEvent = viewEvents.child(u"<eventID>").child(u"")

    viewDispatchQueue = viewEvent.child(u"queue")
    viewDispatchQueueTemplate = prefix.child(u"queue.html")
    viewDispatchQueueJS = prefix.child(u"queue.js")
    viewDispatchQueueRelative = URL.fromText(u"queue")

    viewIncidents = viewEvent.child(u"incidents").child(u"")
    viewIncidentNumber = viewIncidents.child(u"<number>")
    viewIncidentNumberTemplate = prefix.child(u"incident.html")
    viewIncidentNumberJS = prefix.child(u"incident.js")

    viewIncidentReports = prefix.child(u"incident_reports").child(u"")
    viewIncidentReport = viewIncidentReports.child(u"<number>")
    viewIncidentReportTemplate = prefix.child(u"incident_report.html")
    viewIncidentReportJS = prefix.child(u"incident_report.js")
Ejemplo n.º 29
0
Archivo: client.py Proyecto: JayH5/treq
    def request(self, method, url, **kwargs):
        method = method.encode('ascii').upper()

        # Join parameters provided in the URL
        # and the ones passed as argument.
        params = kwargs.get('params')
        if params:
            url = _combine_query_params(url, params)

        if isinstance(url, unicode):
            url = URL.fromText(url).asURI().asText().encode('ascii')

        # Convert headers dictionary to
        # twisted raw headers format.
        headers = kwargs.get('headers')
        if headers:
            if isinstance(headers, dict):
                h = Headers({})
                for k, v in headers.items():

                    if isinstance(k, unicode):
                        k = k.encode('ascii')

                    if isinstance(v, bytes):
                        h.addRawHeader(k, v)
                    elif isinstance(v, unicode):
                        h.addRawHeader(k, v.encode('ascii'))
                    elif isinstance(v, list):
                        cleanHeaders = []
                        for item in v:
                            if isinstance(item, unicode):
                                cleanHeaders.append(item.encode('ascii'))
                            else:
                                cleanHeaders.append(item)
                        h.setRawHeaders(k, cleanHeaders)
                    else:
                        h.setRawHeaders(k, v)

                headers = h
        else:
            headers = Headers({})

        # Here we choose a right producer
        # based on the parameters passed in.
        bodyProducer = None
        data = kwargs.get('data')
        files = kwargs.get('files')
        if files:
            # If the files keyword is present we will issue a
            # multipart/form-data request as it suits better for cases
            # with files and/or large objects.
            files = list(_convert_files(files))
            boundary = str(uuid.uuid4()).encode('ascii')
            headers.setRawHeaders(
                b'content-type', [
                    b'multipart/form-data; boundary=' + boundary])
            if data:
                data = _convert_params(data)
            else:
                data = []

            bodyProducer = multipart.MultiPartProducer(
                data + files, boundary=boundary)
        elif data:
            # Otherwise stick to x-www-form-urlencoded format
            # as it's generally faster for smaller requests.
            if isinstance(data, (dict, list, tuple)):
                headers.setRawHeaders(
                    b'content-type', [b'application/x-www-form-urlencoded'])
                data = urlencode(data, doseq=True)
            bodyProducer = self._data_to_body_producer(data)

        cookies = kwargs.get('cookies', {})

        if not isinstance(cookies, CookieJar):
            cookies = cookiejar_from_dict(cookies)

        cookies = merge_cookies(self._cookiejar, cookies)
        wrapped_agent = CookieAgent(self._agent, cookies)

        if kwargs.get('allow_redirects', True):
            if kwargs.get('browser_like_redirects', False):
                wrapped_agent = BrowserLikeRedirectAgent(wrapped_agent)
            else:
                wrapped_agent = RedirectAgent(wrapped_agent)

        wrapped_agent = ContentDecoderAgent(wrapped_agent,
                                            [(b'gzip', GzipDecoder)])

        auth = kwargs.get('auth')
        if auth:
            wrapped_agent = add_auth(wrapped_agent, auth)

        d = wrapped_agent.request(
            method, url, headers=headers,
            bodyProducer=bodyProducer)

        timeout = kwargs.get('timeout')
        if timeout:
            delayedCall = default_reactor(kwargs.get('reactor')).callLater(
                timeout, d.cancel)

            def gotResult(result):
                if delayedCall.active():
                    delayedCall.cancel()
                return result

            d.addBoth(gotResult)

        if not kwargs.get('unbuffered', False):
            d.addCallback(_BufferedResponse)

        return d.addCallback(_Response, cookies)
Ejemplo n.º 30
0
from twisted.web.client import Agent, HTTPConnectionPool
from twisted.web.http_headers import Headers

from txacme import __version__
from txacme.logging import (
    LOG_ACME_ANSWER_CHALLENGE, LOG_ACME_CONSUME_DIRECTORY,
    LOG_ACME_CREATE_AUTHORIZATION, LOG_ACME_FETCH_CHAIN,
    LOG_ACME_POLL_AUTHORIZATION, LOG_ACME_REGISTER,
    LOG_ACME_REQUEST_CERTIFICATE, LOG_ACME_UPDATE_REGISTRATION,
    LOG_HTTP_PARSE_LINKS, LOG_JWS_ADD_NONCE, LOG_JWS_CHECK_RESPONSE,
    LOG_JWS_GET, LOG_JWS_GET_NONCE, LOG_JWS_HEAD, LOG_JWS_POST,
    LOG_JWS_REQUEST, LOG_JWS_SIGN)
from txacme.util import tap


LETSENCRYPT_DIRECTORY = URL.fromText(
    u'https://acme-v01.api.letsencrypt.org/directory')


LETSENCRYPT_STAGING_DIRECTORY = URL.fromText(
    u'https://acme-staging.api.letsencrypt.org/directory')


# Borrowed from requests, with modifications.

def _parse_header_links(response):
    """
    Parse the links from a Link: header field.

    ..  todo:: Links with the same relation collide at the moment.

    :param bytes value: The header value.
Ejemplo n.º 31
0
def urlFromBytes(b):
    return URL.fromText(b.decode("utf-8"))
    def test_wormhole_tahoe_configuration(
            self,
            customer_email,
            customer_id,
            subscription_id,
            old_secrets,
            introducer_port_number,
            storage_port_number,
    ):
        """
        The wormhole signup mechanism sends a JSON blob of Tahoe-LAFS
        configuration via a magic wormhole identified by a wormhole code
        produced during signup.
        """
        assume(introducer_port_number != storage_port_number)

        provisioned = []
        def provision_subscription(
                smclient, subscription,
        ):
            p = attr.assoc(
                subscription,
                introducer_port_number=introducer_port_number,
                storage_port_number=storage_port_number,
                oldsecrets=old_secrets,
            )
            provisioned.append(p)
            return succeed(p)

        plan_identifier = u"foobar"
        reactor = Clock()
        server = MemoryWormholeServer()

        provisioner = get_provisioner(
            reactor,
            URL.fromText(u"http://subscription-manager/"),
            provision_subscription,
        )

        signup = get_wormhole_signup(
            reactor,
            provisioner,
            server,
            URL.fromText(u"ws://foo.invalid/"),
            FilePath(self.mktemp()),
        )
        d = signup.signup(customer_email, customer_id, subscription_id, plan_identifier)
        wormhole_claim = self.successResultOf(d)

        wh = server.create(
            APPID,
            u"ws://foo.invalid/",
            reactor,
        )

        wh.set_code(wormhole_claim.code)
        d = wh.when_code()

        def foo(x):
            wh.send_message('{"abilities": {"client-v1": {}}}')
            return wh.get_message()
        d.addCallback(foo)

        def bar(arg):
            self.assertEqual(
                loads(arg),
                {"abilities": {"server-v1":{}}}
            )
            return wh.get_message()
        d.addCallback(bar)

        received = self.successResultOf(d)
        received_config = loads(received)
        self.assertThat(
            received_config["introducer"],
            Equals(provisioned[0].external_introducer_furl),
        )
Ejemplo n.º 33
0
class SiteOptions(Options):
    optFlags = [
        # TODO:
        # Make this HTTP-only.
        # Terminate TLS externally.
        # On K8S on AWS, consider using
        # http://kubernetes.io/docs/user-guide/services/#ssl-support-on-aws
    ]

    optParameters = [
        ("stripe-secret-api-key-path", None, None, "A path to a file containing a Stripe API key.", FilePath),
        ("stripe-publishable-api-key-path", None, None, "A path to a file containing a publishable Stripe API key.", FilePath),
        ("site-logs-path", None, None, "A path to a file to which HTTP logs for the site will be written.", FilePath),
        ("wormhole-result-path", None, None,
         "A path to a file to which wormhole interaction results will be written.",
         FilePath,
        ),

        ("redirect-to-port", None, None, "A TCP port number to which to redirect for the TLS site.", int),
        ("subscription-manager", None, None, "Base URL of the subscription manager API.",
         urlFromBytes,
        ),
        ("rendezvous-url", None, URL.fromText(u"ws://wormhole.leastauthority.com:4000/v1"),
         "The URL of the Wormhole Rendezvous server for wormhole-based signup.",
         urlFromBytes,
        ),
        ("metrics-port", None, "tcp:9000",
         "A server endpoint description string on which to run a metrics-exposing server.",
        ),
    ]

    def __init__(self, reactor):
        Options.__init__(self)
        self.reactor = reactor
        self["secure-ports"] = []
        self["insecure-ports"] = []


    opt_eliot_destination = opt_eliot_destination


    def _parse_endpoint(self, label, description):
        """
        Parse a Twisted endpoint description string into an endpoint or
        convert the parse error into a raised L{UsageError}.
        """
        try:
            return serverFromString(self.reactor, description)
        except Exception as e:
            raise UsageError(
                u"Could not parse {label} value {description}: {error}".format(
                    label=label,
                    description=description,
                    error=str(e),
                    )
                )


    def opt_secure_port(self, endpoint_description):
        """
        A Twisted endpoint description string describing an address at
        which to listen for secure web client connections.  The
        website will be served here.  This option must be used at
        least once.
        """
        endpoint = self._parse_endpoint(u"secure-port", endpoint_description)
        self["secure-ports"].append(endpoint)


    def opt_insecure_port(self, endpoint_description):
        """
        A Twisted endpoint description string describing an address at
        which to listen for insecure web client connections.  A
        redirect will be returned sending the client to a secure
        location where the website can be accessed.  This option may
        be used zero or more times.
        """
        endpoint = self._parse_endpoint(u"insecure-port", endpoint_description)
        self["insecure-ports"].append(endpoint)


    def postOptions(self):
        required_options = [
            "stripe-secret-api-key-path",
            "stripe-publishable-api-key-path",
            "subscription-manager",
            "site-logs-path",
            "wormhole-result-path",
        ]
        for option in required_options:
            if self[option] is None:
                raise UsageError("Missing required option --{}".format(option))

        if not self["secure-ports"]:
            raise UsageError(
                u"Use --secure-port at least once to specify an address for "
                u"the website."
            )
        if self["redirect-to-port"] is not None and not self["insecure-ports"]:
            raise UsageError(
                u"Use --insecure-port at least once or there is no server to "
                u"use --redirect-to-port value."
            )

        p = self["site-logs-path"].parent()
        if not p.isdir():
            p.makedirs()
Ejemplo n.º 34
0
    def test_wormhole_tahoe_configuration(
            self,
            customer_email,
            customer_id,
            subscription_id,
            old_secrets,
            introducer_port_number,
            storage_port_number,
    ):
        """
        The wormhole signup mechanism sends a JSON blob of Tahoe-LAFS
        configuration via a magic wormhole identified by a wormhole code
        produced during signup.
        """
        assume(introducer_port_number != storage_port_number)

        provisioned = []
        def provision_subscription(
                smclient, subscription,
        ):
            p = attr.assoc(
                subscription,
                introducer_port_number=introducer_port_number,
                storage_port_number=storage_port_number,
                oldsecrets=old_secrets,
            )
            provisioned.append(p)
            return succeed(p)

        plan_identifier = u"foobar"
        reactor = Clock()
        server = MemoryWormholeServer()

        provisioner = get_provisioner(
            reactor,
            URL.fromText(u"http://subscription-manager/"),
            provision_subscription,
        )

        signup = get_wormhole_signup(
            reactor,
            provisioner,
            server,
            URL.fromText(u"ws://foo.invalid/"),
            FilePath(self.mktemp()),
        )
        d = signup.signup(customer_email, customer_id, subscription_id, plan_identifier)
        wormhole_claim = self.successResultOf(d)

        wh = server.create(
            u"tahoe-lafs.org/tahoe-lafs/v1",
            u"ws://foo.invalid/",
            reactor,
        )

        wh.set_code(wormhole_claim.code)
        d = wh.when_code()

        def foo(x):
            wh.send_message('{"abilities": {"client-v1": {}}}')
            return wh.get_message()
        d.addCallback(foo)

        def bar(arg):
            self.assertEqual(
                loads(arg),
                {"abilities": {"server-v1":{}}}
            )
            return wh.get_message()
        d.addCallback(bar)

        received = self.successResultOf(d)
        received_config = loads(received)
        self.assertThat(
            received_config["introducer"],
            Equals(provisioned[0].external_introducer_furl),
        )
 def _url(self, *segments):
     return URL.fromText(self.endpoint.decode("utf-8")).child(
         *segments).asURI().asText().encode("ascii")
Ejemplo n.º 36
0
def urlFromBytes(b):
    return URL.fromText(b.decode("utf-8"))
Ejemplo n.º 37
0
def get_things_done():
    """
    Here is where the client part is setup and action is done.
    """
    responders = yield start_responders()

    # We first validate the directory.
    account_key = _get_account_key()
    try:
        client = yield Client.from_url(
            reactor,
            URL.fromText(acme_url.decode('utf-8')),
            key=JWKRSA(key=account_key),
            alg=RS256,
        )
    except Exception as error:
        print('\n\nFailed to connect to ACME directory. %s' % (error, ))
        yield reactor.stop()
        defer.returnValue(None)

    # Then we register a new account or update an existing account.
    # First register a new account with a contact set, then using the same
    # key call register with a different contact and see that it was updated.
    response = yield client.start(
        email='[email protected],[email protected]')

    print('Account URI: %s' % (response.uri, ))
    print('Account contact: %s' % (response.body.contact, ))

    # We request a single certificate for a list of domains and get an "order"
    cert_key = generate_private_key('rsa')
    orderr = yield client.submit_order(cert_key, requested_domains)

    # Each order had a list of "authorizations" for which the challenge needs
    # to be validated.
    for authorization in orderr.authorizations:
        try:
            # Make sure all ACME server requests are sequential.
            # For now, answering to the challenges in parallel will not work.
            yield answer_challenge(authorization,
                                   client,
                                   responders,
                                   clock=reactor)
        except Exception as error:
            print('\n\nFailed to validate a challenge. %s' % (error, ))
            yield reactor.stop()
            defer.returnValue(None)

    certificate = yield get_certificate(orderr, client, clock=reactor)

    print('Got a new cert:\n')
    print(certificate.body)

    cert_key_pem = cert_key.private_bytes(
        encoding=serialization.Encoding.PEM,
        format=serialization.PrivateFormat.PKCS8,
        encryption_algorithm=serialization.NoEncryption(),
    )

    # Cleanup the client and disconnect any persistent connection to the
    # ACME server.
    yield client.stop()

    # The new certificate is available and we can start a demo HTTPS server
    # using it.
    yield start_https_demo_server(cert_key_pem, certificate.body)
    print('txacme demo done.')
Ejemplo n.º 38
0
from twisted.python.url import URL

LETSENCRYPT_DIRECTORY = URL.fromText(
    u'https://acme-v02.api.letsencrypt.org/directory')

LETSENCRYPT_STAGING_DIRECTORY = URL.fromText(
    u'https://acme-staging-v02.api.letsencrypt.org/directory')

__all__ = ['LETSENCRYPT_DIRECTORY', 'LETSENCRYPT_STAGING_DIRECTORY']
Ejemplo n.º 39
0
    def fetch_title(self, url, hostname_tag=False, friendly_errors=False):
        """Fetch the document at *url* and return a `Deferred` yielding
        the document title or summary as a Unicode string.  *url* may be
        a Unicode string IRI, a byte string URI, or a Twisted `URL`.

        If *hostname_tag* is true, prefix the extracted title with the
        hostname of the initially requested URI or IRI in the form that
        was originally provided, as well as the hostname of the final
        ASCII-only URI if it differs due to redirects or normalization.

        If *friendly_errors* is true, catch common connection errors and
        return a description of the error as the extracted title instead
        of reraising.  Otherwise, all errors bubble to the caller.
        """
        title = None
        if isinstance(url, unicode):
            url = URL.fromText(url)
        elif isinstance(url, str):
            url = URL.fromText(url.decode('ascii'))
        current = url
        response = None
        for _ in xrange(self.max_soft_redirects):
            last_response = response
            # This encoding should be safe, since asURI() only returns
            # URIs with ASCII code points.
            request = self.agent.request(
                'GET', current.asURI().asText().encode('ascii'))
            if friendly_errors:
                request.addErrback(describe_error)
            response = yield request
            if isinstance(response, basestring):
                # We got an error message from describe_error.  Bail.
                title = response
                break
            response.setPreviousResponse(last_response)
            content_type = cgi.parse_header(
                response.headers.getRawHeaders('Content-Type', [''])[0])[0]
            if content_type in self.extractors:
                extractor = self.extractors[content_type]
                extracted = yield extractor.extract(response)
                if isinstance(extracted, Redirect):
                    current = URL.fromText(
                        response.request.absoluteURI.decode('ascii')).click(
                        extracted.location)
                    continue
                title = extracted
            # The only case where we'd want to loop again is when the
            # response returned is a soft redirect.
            break
        else:
            if friendly_errors:
                title = u'Encountered too many redirects.'
            else:
                raise ResponseFailed([Failure(InfiniteRedirection(
                    599, 'Too many soft redirects',
                    location=current.asURI().asText().encode('ascii')))])
        if title is None:
            title = u'{} document'.format(content_type or u'Unknown')
            if response.length is not UNKNOWN_LENGTH:
                title += u' ({})'.format(filesize(response.length))
        if hostname_tag:
            tag = url.host
            if isinstance(response, Response):
                initial = url.host
                final = URL.fromText(
                    response.request.absoluteURI.decode('ascii')).host
                if initial != final:
                    tag = u'{} \u2192 {}'.format(initial, final)
            title = u'[{}] {}'.format(tag, title)
        returnValue(title)
Ejemplo n.º 40
0
    def request(self, method, url, **kwargs):
        method = method.encode('ascii').upper()

        # Join parameters provided in the URL
        # and the ones passed as argument.
        params = kwargs.get('params')
        if params:
            url = _combine_query_params(url, params)

        if isinstance(url, unicode):
            url = URL.fromText(url).asURI().asText().encode('ascii')

        # Convert headers dictionary to
        # twisted raw headers format.
        headers = kwargs.get('headers')
        if headers:
            if isinstance(headers, dict):
                h = Headers({})
                for k, v in headers.items():
                    if isinstance(v, (bytes, unicode)):
                        h.addRawHeader(k, v)
                    elif isinstance(v, list):
                        h.setRawHeaders(k, v)

                headers = h
        else:
            headers = Headers({})

        # Here we choose a right producer
        # based on the parameters passed in.
        bodyProducer = None
        data = kwargs.get('data')
        files = kwargs.get('files')
        # since json=None needs to be serialized as 'null', we need to
        # explicitly check kwargs for this key
        has_json = 'json' in kwargs

        if files:
            # If the files keyword is present we will issue a
            # multipart/form-data request as it suits better for cases
            # with files and/or large objects.
            files = list(_convert_files(files))
            boundary = str(uuid.uuid4()).encode('ascii')
            headers.setRawHeaders(
                b'content-type', [
                    b'multipart/form-data; boundary=' + boundary])
            if data:
                data = _convert_params(data)
            else:
                data = []

            bodyProducer = multipart.MultiPartProducer(
                data + files, boundary=boundary)
        elif data:
            # Otherwise stick to x-www-form-urlencoded format
            # as it's generally faster for smaller requests.
            if isinstance(data, (dict, list, tuple)):
                headers.setRawHeaders(
                    b'content-type', [b'application/x-www-form-urlencoded'])
                data = urlencode(data, doseq=True)
            bodyProducer = self._data_to_body_producer(data)
        elif has_json:
            # If data is sent as json, set Content-Type as 'application/json'
            headers.setRawHeaders(
                b'content-type', [b'application/json; charset=UTF-8'])
            content = kwargs['json']
            json = json_dumps(content, separators=(u',', u':')).encode('utf-8')
            bodyProducer = self._data_to_body_producer(json)

        cookies = kwargs.get('cookies', {})

        if not isinstance(cookies, CookieJar):
            cookies = cookiejar_from_dict(cookies)

        cookies = merge_cookies(self._cookiejar, cookies)
        wrapped_agent = CookieAgent(self._agent, cookies)

        if kwargs.get('allow_redirects', True):
            if kwargs.get('browser_like_redirects', False):
                wrapped_agent = BrowserLikeRedirectAgent(wrapped_agent)
            else:
                wrapped_agent = RedirectAgent(wrapped_agent)

        wrapped_agent = ContentDecoderAgent(wrapped_agent,
                                            [(b'gzip', GzipDecoder)])

        auth = kwargs.get('auth')
        if auth:
            wrapped_agent = add_auth(wrapped_agent, auth)

        d = wrapped_agent.request(
            method, url, headers=headers,
            bodyProducer=bodyProducer)

        timeout = kwargs.get('timeout')
        if timeout:
            delayedCall = default_reactor(kwargs.get('reactor')).callLater(
                timeout, d.cancel)

            def gotResult(result):
                if delayedCall.active():
                    delayedCall.cancel()
                return result

            d.addBoth(gotResult)

        if not kwargs.get('unbuffered', False):
            d.addCallback(_BufferedResponse)

        return d.addCallback(_Response, cookies)
Ejemplo n.º 41
0
    def test_emailed_introducer_furl(
            self,
            customer_email,
            customer_id,
            subscription_id,
            old_secrets,
            introducer_port_number,
            storage_port_number,
    ):
        """
        The email signup mechanism sends an activation email including an
        introducer furl which points at the server and port identified by the
        activated subscription detail object.
        """
        assume(introducer_port_number != storage_port_number)

        emails = []

        def provision_subscription(
                smclient, subscription,
        ):
            return succeed(
                attr.assoc(
                    subscription,
                    introducer_port_number=introducer_port_number,
                    storage_port_number=storage_port_number,
                    oldsecrets=old_secrets,
                ),
            )

        def send_signup_confirmation(
                customer_email, external_introducer_furl, customer_keyinfo, stdout, stderr,
        ):
            emails.append((customer_email, "success", external_introducer_furl))
            return succeed(None)

        def send_notify_failure(
                reason, customer_email, logfilename, stdout, stderr,
        ):
            emails.append((customer_email, "failure", reason))
            return succeed(None)

        plan_identifier = u"foobar"

        reactor = object()
        signup = get_email_signup(
            reactor,
            get_provisioner(
                reactor,
                URL.fromText(u"http://subscription-manager/"),
                provision_subscription,
            ),
            send_signup_confirmation,
            send_notify_failure,
        )
        d = signup.signup(customer_email, customer_id, subscription_id, plan_identifier)
        self.successResultOf(d)

        [(recipient, result, rest)] = emails
        self.expectThat(recipient, Equals(customer_email))
        self.expectThat(result, Equals("success"))

        def get_hint_port(furl):
            tub_id, location_hints, name = decode_furl(furl)
            host, port = location_hints[0].split(u":")
            return int(port)

        self.expectThat(
            rest,
            AfterPreprocessing(
                get_hint_port,
                Equals(introducer_port_number),
            ),
        )
Ejemplo n.º 42
0
class ExternalMixIn(object):
    """
    Mix-in for cached external resources.
    """

    bootstrapVersionNumber = u"3.3.7"
    jqueryVersionNumber = u"3.1.0"
    dataTablesVersionNumber = u"1.10.12"
    momentVersionNumber = u"2.14.1"
    lscacheVersionNumber = u"1.0.5"

    bootstrapVersion = u"bootstrap-{}-dist".format(bootstrapVersionNumber)
    jqueryVersion = u"jquery-{}".format(jqueryVersionNumber)
    dataTablesVersion = u"DataTables-{}".format(dataTablesVersionNumber)
    momentVersion = u"moment-{}".format(momentVersionNumber)
    lscacheVersion = u"lscache-{}".format(lscacheVersionNumber)

    bootstrapSourceURL = URL.fromText(
        u"https://github.com/twbs/bootstrap/releases/download/v{n}/{v}.zip".
        format(n=bootstrapVersionNumber, v=bootstrapVersion))

    jqueryJSSourceURL = URL.fromText(
        u"https://code.jquery.com/{v}.min.js".format(n=jqueryVersionNumber,
                                                     v=jqueryVersion))

    jqueryMapSourceURL = URL.fromText(
        u"https://code.jquery.com/{v}.min.map".format(n=jqueryVersionNumber,
                                                      v=jqueryVersion))

    dataTablesSourceURL = URL.fromText(
        u"https://datatables.net/releases/DataTables-{n}.zip".format(
            n=dataTablesVersionNumber, v=dataTablesVersion))

    momentJSSourceURL = URL.fromText(
        u"https://cdnjs.cloudflare.com/ajax/libs/moment.js/{n}/moment.min.js".
        format(n=momentVersionNumber))

    lscacheJSSourceURL = URL.fromText(
        u"https://raw.githubusercontent.com/pamelafox/lscache/{n}/"
        u"lscache.min.js".format(n=lscacheVersionNumber))

    @route(URLs.bootstrapBase.asText(), methods=("HEAD", "GET"), branch=True)
    @staticResource
    def bootstrapResource(self, request):
        requestURL = URL.fromText(request.uri)

        # Remove URL prefix
        names = requestURL.path[len(URLs.bootstrapBase.path) - 1:]

        request.setHeader(HeaderName.contentType.value, ContentType.CSS.value)
        return self.cachedZippedResource(request, self.bootstrapSourceURL,
                                         self.bootstrapVersion,
                                         self.bootstrapVersion, *names)

    @route(URLs.jqueryJS.asText(), methods=("HEAD", "GET"))
    @staticResource
    def jqueryJSResource(self, request):
        request.setHeader(HeaderName.contentType.value,
                          ContentType.JavaScript.value)
        return self.cachedResource(
            request,
            self.jqueryJSSourceURL,
            "{}.min.js".format(self.jqueryVersion),
        )

    @route(URLs.jqueryMap.asText(), methods=("HEAD", "GET"))
    @staticResource
    def jqueryMapResource(self, request):
        request.setHeader(HeaderName.contentType.value, ContentType.JSON.value)
        return self.cachedResource(
            request,
            self.jqueryMapSourceURL,
            "{}.min.map".format(self.jqueryVersion),
        )

    @route(URLs.dataTablesBase.asText(), methods=("HEAD", "GET"), branch=True)
    @staticResource
    def dataTablesResource(self, request):
        requestURL = URL.fromText(request.uri)

        # Remove URL prefix
        names = requestURL.path[len(URLs.dataTablesBase.path) - 1:]

        request.setHeader(HeaderName.contentType.value, ContentType.CSS.value)
        return self.cachedZippedResource(request, self.dataTablesSourceURL,
                                         self.dataTablesVersion,
                                         self.dataTablesVersion, *names)

    @route(URLs.momentJS.asText(), methods=("HEAD", "GET"))
    @staticResource
    def momentJSResource(self, request):
        request.setHeader(HeaderName.contentType.value,
                          ContentType.JavaScript.value)
        return self.cachedResource(
            request,
            self.momentJSSourceURL,
            "{}.min.js".format(self.momentVersion),
        )

    @route(URLs.lscacheJS.asText(), methods=("HEAD", "GET"))
    @staticResource
    def lscacheJSResource(self, request):
        request.setHeader(HeaderName.contentType.value,
                          ContentType.JavaScript.value)
        return self.cachedResource(
            request,
            self.lscacheJSSourceURL,
            "{}.min.js".format(self.lscacheVersion),
        )

    @inlineCallbacks
    def cacheFromURL(self, url, name):
        cacheDir = self.config.CachedResources

        if not cacheDir.isdir():
            cacheDir.createDirectory()

        destination = cacheDir.child(name)

        if not destination.exists():
            tmp = destination.temporarySibling(extension=".tmp")
            try:
                yield downloadPage(url.asText().encode("utf-8"), tmp.open("w"))
            except:
                self.log.failure("Download failed for {url}", url=url)
                try:
                    tmp.remove()
                except (OSError, IOError):
                    pass
            else:
                tmp.moveTo(destination)

        returnValue(destination)

    @inlineCallbacks
    def cachedResource(self, request, url, name):
        filePath = yield self.cacheFromURL(url, name)

        try:
            returnValue(filePath.getContent())
        except (OSError, IOError) as e:
            self.log.error(
                "Unable to open file {filePath.path}: {error}",
                filePath=filePath,
                error=e,
            )
            returnValue(self.notFoundResource(request))

    @inlineCallbacks
    def cachedZippedResource(self, request, url, archiveName, name, *names):
        archivePath = yield self.cacheFromURL(url,
                                              "{0}.zip".format(archiveName))

        try:
            filePath = ZipArchive(archivePath.path)
        except BadZipfile as e:
            self.log.error(
                "Corrupt zip archive {archive.path}: {error}",
                archive=archivePath,
                error=e,
            )
            try:
                archivePath.remove()
            except (OSError, IOError):
                pass
            returnValue(self.notFoundResource(request))
        except (OSError, IOError) as e:
            self.log.error(
                "Unable to open zip archive {archive.path}: {error}",
                archive=archivePath,
                error=e,
            )
            returnValue(self.notFoundResource(request))

        filePath = filePath.child(name)
        for name in names:
            filePath = filePath.child(name)

        try:
            returnValue(filePath.getContent())
        except KeyError:
            self.log.error(
                "File not found in ZIP archive: {filePath.path}",
                filePath=filePath,
                archive=archivePath,
            )
            returnValue(self.notFoundResource(request))
    def test_emailed_introducer_furl(
            self,
            customer_email,
            customer_id,
            subscription_id,
            old_secrets,
            introducer_port_number,
            storage_port_number,
    ):
        """
        The email signup mechanism sends an activation email including an
        introducer furl which points at the server and port identified by the
        activated subscription detail object.
        """
        assume(introducer_port_number != storage_port_number)

        emails = []

        def provision_subscription(
                smclient, subscription,
        ):
            return succeed(
                attr.assoc(
                    subscription,
                    introducer_port_number=introducer_port_number,
                    storage_port_number=storage_port_number,
                    oldsecrets=old_secrets,
                ),
            )

        def send_signup_confirmation(
                customer_email, external_introducer_furl, customer_keyinfo, stdout, stderr,
        ):
            emails.append((customer_email, "success", external_introducer_furl))
            return succeed(None)

        def send_notify_failure(
                reason, customer_email, logfilename, stdout, stderr,
        ):
            emails.append((customer_email, "failure", reason))
            return succeed(None)

        plan_identifier = u"foobar"

        reactor = object()
        signup = get_email_signup(
            reactor,
            get_provisioner(
                reactor,
                URL.fromText(u"http://subscription-manager/"),
                provision_subscription,
            ),
            send_signup_confirmation,
            send_notify_failure,
        )
        d = signup.signup(customer_email, customer_id, subscription_id, plan_identifier)
        self.successResultOf(d)

        [(recipient, result, rest)] = emails
        self.expectThat(recipient, Equals(customer_email))
        self.expectThat(result, Equals("success"))

        def get_hint_port(furl):
            tub_id, location_hints, name = decode_furl(furl)
            host, port = location_hints[0].split(u":")
            return int(port)

        self.expectThat(
            rest,
            AfterPreprocessing(
                get_hint_port,
                Equals(introducer_port_number),
            ),
        )