def test_cookie_set():
    """
    test that we get a cookie relating to the space we are in
    """
    store = get_store(config)
    hostname = "foo.0.0.0.0:8080"
    user = User(u"f\u00F6o")
    user.set_password("foobar")
    store.put(user)

    user_cookie = get_auth(u"f\u00F6o", "foobar")

    response, content = http.request(
        "http://foo.0.0.0.0:8080/", method="GET", headers={"Cookie": 'tiddlyweb_user="******"' % user_cookie}
    )

    assert response["status"] == "200", content

    time = datetime.utcnow().strftime("%Y%m%d%H")
    cookie = "csrf_token=%s:%s:%s" % (
        time,
        user.usersign,
        sha("%s:%s:%s:%s" % (user.usersign, time, hostname, config["secret"])).hexdigest(),
    )
    assert response["set-cookie"] == quote(cookie.encode("utf-8"), safe=".!~*'():=")
def _expand_recipe(content, url=''):
    """
    Expand a recipe into a list of usable URLs.

    Content is a string, potentially with URL quoted strings.
    """
    urls = []
    for line in content.splitlines():
        line = line.lstrip().rstrip()
        try:
            target_type, target = line.split(':', 1)
        except ValueError:
            continue  # blank line in recipe
        if target_type in ACCEPTED_RECIPE_TYPES:
            target = target.lstrip().rstrip()
            # translate well-known variables
            for name in COOK_VARIABLES:
                target = target.replace('$%s' % name, COOK_VARIABLES[name])
            # Check to see if the target is a URL (has a scheme)
            # if not we want to join it to the current url before
            # carrying on.
            scheme, _ = splittype(target)
            if not scheme:
                if not '%' in target:
                    target = quote(target)
                target = urljoin(url, target)
            if target_type == 'recipe':
                urls.extend(recipe_to_urls(target))
            else:
                urls.append(target)
    return urls
Пример #3
0
    def recipe_as(self, recipe):
        """
        :py:class:`Recipe <tiddlyweb.model.recipe.Recipe>` as HTML,
        including a link to the tiddlers within.
        """
        self.environ['tiddlyweb.title'] = 'Recipe %s' % recipe.name
        lines = []
        for bag, filter_string in recipe.get_recipe():
            line = '<li><a href="'
            line += '%s/bags/%s/tiddlers' % (self._server_prefix(),
                                             encode_name(bag))
            if filter_string:
                line += '?%s' % quote(filter_string.encode('utf-8'),
                                      safe=':=;')
            line += '">bag: %s filter:%s</a></li>' % (bag, filter_string)
            lines.append(line)
        output = "\n".join(lines)
        tiddler_link = '%s/tiddlers' % encode_name(recipe.name)
        return """
%s
<div class="tiddlerslink"><a href="%s">Tiddlers in Recipe</a></div>
<div id="recipedesc" class="description">%s</div>
<ul id="recipe" class="listing">
%s
</ul>
%s
""" % (self._header(), tiddler_link, recipe.desc, output, self._footer())
Пример #4
0
    def recipe_as(self, recipe):
        """
        Dump a :py:class:`recipe <tiddlyweb.model.recipe.Recipe>` as text.
        """
        policy_dict = dict([(key, getattr(recipe.policy, key))
                            for key in Policy.attributes])
        lines = [
            'desc: %s' % recipe.desc,
            'policy: %s' % simplejson.dumps(policy_dict), ''
        ]

        for bag, filter_string in recipe.get_recipe():
            line = ''
            if not get_bag_retriever(self.environ, bag):
                # If there is a retriever for this bag name then
                # we want to write its name straight.
                line += '/bags/%s/tiddlers' % quote(bag.encode('utf-8'),
                                                    safe='')
            else:
                line += bag
            if filter_string:
                line += '?%s' % filter_string
            lines.append(line)

        return "\n".join(lines)
Пример #5
0
    def recipe_as(self, recipe):
        """
        :py:class:`Recipe <tiddlyweb.model.recipe.Recipe>` as HTML,
        including a link to the tiddlers within.
        """
        self.environ['tiddlyweb.title'] = 'Recipe %s' % recipe.name
        lines = []
        for bag, filter_string in recipe.get_recipe():
            line = '<li><a href="'
            line += '%s/bags/%s/tiddlers' % (
                    self._server_prefix(), encode_name(bag))
            if filter_string:
                line += '?%s' % quote(
                        filter_string.encode('utf-8'), safe=':=;')
            line += '">bag: %s filter:%s</a></li>' % (bag, filter_string)
            lines.append(line)
        output = "\n".join(lines)
        tiddler_link = '%s/tiddlers' % encode_name(recipe.name)
        return """
%s
<div class="tiddlerslink"><a href="%s">Tiddlers in Recipe</a></div>
<div id="recipedesc" class="description">%s</div>
<ul id="recipe" class="listing">
%s
</ul>
%s
""" % (self._header(), tiddler_link, recipe.desc, output, self._footer())
Пример #6
0
def _expand_recipe(content, url=''):
    """
    Expand a recipe into a list of usable URLs.

    Content is a string, potentially with URL quoted strings.
    """
    urls = []
    for line in content.splitlines():
        line = line.lstrip().rstrip()
        try:
            target_type, target = line.split(':', 1)
        except ValueError:
            continue  # blank line in recipe
        if target_type in ACCEPTED_RECIPE_TYPES:
            target = target.lstrip().rstrip()
            # translate well-known variables
            for name in COOK_VARIABLES:
                target = target.replace('$%s' % name, COOK_VARIABLES[name])
            # Check to see if the target is a URL (has a scheme)
            # if not we want to join it to the current url before
            # carrying on.
            scheme, _ = splittype(target)
            if not scheme:
                if not '%' in target:
                    target = quote(target)
                target = urljoin(url, target)
            if target_type == 'recipe':
                urls.extend(recipe_to_urls(target))
            else:
                urls.append(target)
    return urls
Пример #7
0
def _challenger_url(environ, system):
    """
    Return the proper URL for a specific challenger system.
    """
    default_redirect = "%s/" % environ["tiddlyweb.config"]["server_prefix"]
    redirect = environ["tiddlyweb.query"].get("tiddlyweb_redirect", [default_redirect])[0]
    redirect = "?tiddlyweb_redirect=%s" % quote(redirect.encode("utf-8"), safe="")
    return "%s/challenge/%s%s" % (server_base_url(environ), system, redirect)
Пример #8
0
def _challenger_url(environ, system):
    """
    Return the proper URL for a specific challenger system.
    """
    default_redirect = '%s/' % environ['tiddlyweb.config']['server_prefix']
    redirect = (environ['tiddlyweb.query'].get('tiddlyweb_redirect',
            [default_redirect])[0])
    redirect = '?tiddlyweb_redirect=%s' % quote(
            redirect.encode('utf-8'), safe='')
    return '%s/challenge/%s%s' % (server_base_url(environ), system, redirect)
Пример #9
0
def _challenger_url(environ, system):
    """
    Return the proper URL for a specific challenger system.
    """
    default_redirect = '%s/' % environ['tiddlyweb.config']['server_prefix']
    redirect = (environ['tiddlyweb.query'].get('tiddlyweb_redirect',
                                               [default_redirect])[0])
    redirect = '?tiddlyweb_redirect=%s' % quote(redirect.encode('utf-8'),
                                                safe='')
    return '%s/challenge/%s%s' % (server_base_url(environ), system, redirect)
Пример #10
0
def post_tiddler_to_container(environ, start_response):
    """
    entry point for recipes/foo/tiddlers or bags/foo/tiddlers

    we have included the tiddler name in the form,
    so get that and carry on as normal
    """
    form = environ['tiddlyweb.query']

    def get_name():
        if 'title' in form:
            return retrieve_item(form, 'title')
        else:
            files = environ['tiddlyweb.input_files']
            return files[0].filename

    try:
        tiddler_name = get_name()
    except (KeyError, IndexError):
        tiddler_name = str(uuid4())

    Serialization.form = form
    try:
        redirect = environ['tiddlyweb.query'].pop('redirect')
    except KeyError:
        redirect = None
    if redirect:
        redirect = redirect[0]
        if '?' in redirect and not redirect.endswith('?'):
            redirect += '&'
        else:
            redirect += '?'
        redirect += '.no-cache=%s' % uuid4()
        # Extra safe characters used to preserve query strings.
        redirect = quote(redirect.encode('utf-8'), safe="/?&=:.!~*'()")

    #mock up some objects that tiddlyweb.web.handler.tiddler.put requires
    environ['wsgiorg.routing_args'][1]['tiddler_name'] = tiddler_name
    environ['REQUEST_METHOD'] = 'PUT'
    environ['wsgi.input'] = StringIO('dummy input')
    def dummy_start_response(response_code, *args):
        """
        start_response may only be called once.
        We may need it to be a redirect instead of a 204
        """
        if not response_code.startswith('204'):
            start_response(response_code, *args)
        elif redirect:
            response = [('Location', redirect)]
            start_response('303 See Other', response)
        else:
            start_response(response_code, *args)

    return put(environ, dummy_start_response)
Пример #11
0
def _encode_filename(filename):
    """
    utf-8 encode, then url escape, some filename,
    making it easy to use on various filesystems.

    Also check for no ../ in filenames.
    """

    if not filename or '../' in filename:
        raise StoreEncodingError('invalid name for entity')
    return quote(filename.encode('utf-8'), safe=".!~*'()")
Пример #12
0
def _encode_filename(filename):
    """
    utf-8 encode, then url escape, some filename,
    making it easy to use on various filesystems.

    Also check for no ../ in filenames.
    """

    if not filename or '../' in filename:
        raise StoreEncodingError('invalid name for entity')
    return quote(filename.encode('utf-8'), safe=".!~*'()")
Пример #13
0
def _challenge_url(environ):
    """
    Generate the URL of the challenge system
    so that GET requests are redirected to the
    right place.
    """
    script_name = environ.get('SCRIPT_NAME', '')
    query_string = environ.get('QUERY_STRING', None)
    redirect = script_name
    if query_string:
        redirect += '?%s' % query_string
    redirect = quote(redirect, safe='')
    return '%s/challenge?tiddlyweb_redirect=%s' % (
            server_base_url(environ), redirect)
def test_post_data_form_urlencoded():
    """
    test that a form POST requires a nonce
    test using application/x-www-form-urlencoded
    """
    store = get_store(config)
    hostname = "foo.0.0.0.0:8080"
    user = User(u"f\u00F6o")
    user.set_password("foobar")
    store.put(user)
    store.put(Bag("foo_public"))
    timestamp = datetime.utcnow().strftime("%Y%m%d%H")
    secret = config["secret"]
    nonce = "%s:%s:%s" % (
        timestamp,
        user.usersign,
        sha("%s:%s:%s:%s" % (user.usersign, timestamp, hostname, secret)).hexdigest(),
    )

    user_cookie = get_auth(u"f\u00F6o", "foobar")
    csrf_token = 'csrf_token="%s"' % quote(nonce.encode("utf-8"), safe=".!~*'():")
    data = "title=foobar&text=hello%20world"

    print "nc", nonce, csrf_token
    # test success
    response, content = http.request(
        "http://foo.0.0.0.0:8080/bags/foo_public/tiddlers",
        method="POST",
        headers={
            "Content-type": "application/x-www-form-urlencoded",
            "Cookie": 'tiddlyweb_user="******"; %s' % (user_cookie, csrf_token),
        },
        body="%s&csrf_token=%s" % (data, encode_name(nonce)),
    )
    assert response["status"] == "204", content

    # test failure
    response, content = http.request(
        "http://0.0.0.0:8080/bags/foo_public/tiddlers",
        method="POST",
        headers={"Content-type": "application/x-www-form-urlencoded", "Cookie": 'tiddlyweb_user="******"' % user_cookie},
        body="%s" % data,
    )
    assert response["status"] == "400", content
Пример #15
0
    def _log_app(self, environ, start_response):
        req_uri = quote(environ.get('SCRIPT_NAME', '')
                + environ.get('PATH_INFO', ''))
        if environ.get('QUERY_STRING'):
            req_uri += '?' + environ['QUERY_STRING']

        def replacement_start_response(status, headers, exc_info=None):
            """
            We need to gaze at the content-length, if set, to
            write log info.
            """
            size = None
            for name, value in headers:
                if name.lower() == 'content-length':
                    size = value
            self.write_log(environ, req_uri, status, size)
            return start_response(status, headers, exc_info)

        return self.application(environ, replacement_start_response)
def test_nonce_not_left_over():
    """
    Test that the nonce is not left over in the tiddler after a POST
    i.e. check that it is removed before the request continues
    """
    store = get_store(config)
    hostname = "foo.0.0.0.0:8080"
    user = User(u"f\u00F6o")
    user.set_password("foobar")
    store.put(user)
    timestamp = datetime.utcnow().strftime("%Y%m%d%H")
    secret = config["secret"]
    nonce = "%s:%s:%s" % (
        timestamp,
        user.usersign,
        sha("%s:%s:%s:%s" % (user.usersign, timestamp, hostname, secret)).hexdigest(),
    )

    user_cookie = get_auth(u"f\u00F6o", "foobar")
    data = "title=foobar&text=hello%20world&extra_field=baz"

    nonce = quote(nonce.encode("utf-8"), safe=".!~*'():")

    # test success
    response, _ = http.request(
        "http://foo.0.0.0.0:8080/bags/foo_public/tiddlers",
        method="POST",
        headers={"Content-type": "application/x-www-form-urlencoded", "Cookie": 'tiddlyweb_user="******"' % user_cookie},
        body="%s&csrf_token=%s" % (data, nonce),
    )
    assert response["status"] == "204"

    new_tiddler = Tiddler("foobar")
    new_tiddler.bag = "foo_public"
    new_tiddler = store.get(new_tiddler)

    assert new_tiddler.title == "foobar"
    assert new_tiddler.text == "hello world"
    assert new_tiddler.fields.get("extra_field") == "baz"
    assert new_tiddler.fields.get("nonce") is None
Пример #17
0
 def fake_start_response(status, headers, exc_info=None):
     """
     add a csrf_token header (if we need to)
     """
     user_cookie = Cookie.SimpleCookie()
     user_cookie.load(str(environ.get('HTTP_COOKIE', '')))
     csrf_cookie = user_cookie.get('csrf_token')
     timestamp = ''
     cookie_user = None
     if csrf_cookie:
         try:
             timestamp, cookie_user, _ = csrf_cookie.value.split(':', 2)
             cookie_user = unquote(cookie_user)
         except ValueError:
             timestamp = ''
             cookie_user = ''
     username = environ['tiddlyweb.usersign']['name']
     now = datetime.utcnow().strftime('%Y%m%d%H')
     if username == 'GUEST':
         if cookie_user:
             if 'MSIE' in environ.get('HTTP_USER_AGENT', ''):
                 expires = 'Expires=%s;' % datetime.strftime(
                         datetime.utcnow() - timedelta(hours=1),
                         '%a, %d-%m-%y %H:%M:%S GMT')
             else:
                 expires = 'Max-Age=0;'
             set_cookie = 'csrf_token=; %s' % expires
             headers.append(('Set-Cookie', set_cookie))
         else:
             start_response(status, headers, exc_info)
             return
     elif now != timestamp or cookie_user != username:
         user, space, secret = get_nonce_components(environ)
         nonce = gen_nonce(user, space, now, secret)
         # URL encode cookie for safe Unicode usernames
         set_cookie = 'csrf_token=%s' % quote(nonce.encode('utf-8'),
                 safe=".!~*'():")
         headers.append(('Set-Cookie', set_cookie))
     start_response(status, headers, exc_info)
Пример #18
0
def get_url_handle(url):
    """
    Open the url using urllib2.urlopen. If the url is a filepath
    transform it into a file url.
    """
    try:
        try:
            try:
                handle = urlopen(url)
            except (URLError, OSError):
                (scheme, netloc, path, params, query, fragment) = urlparse(url)
                path = quote(path)
                newurl = urlunparse(
                    (scheme, netloc, path, params, query, fragment))
                handle = urlopen(newurl)
        except ValueError:
            # If ValueError happens again we want it to raise
            url = 'file://' + os.path.abspath(url)
            handle = urlopen(url)
        return url, handle
    except HTTPError as exc:
        raise ValueError('%s: %s' % (exc, url))
Пример #19
0
    def recipe_as(self, recipe):
        """
        Dump a :py:class:`recipe <tiddlyweb.model.recipe.Recipe>` as text.
        """
        policy_dict = dict([(key, getattr(recipe.policy, key)) for
                key in Policy.attributes])
        lines = ['desc: %s' % recipe.desc, 'policy: %s' %
                simplejson.dumps(policy_dict), '']

        for bag, filter_string in recipe.get_recipe():
            line = ''
            if not get_bag_retriever(self.environ, bag):
                # If there is a retriever for this bag name then
                # we want to write its name straight.
                line += '/bags/%s/tiddlers' % quote(
                        bag.encode('utf-8'), safe='')
            else:
                line += bag
            if filter_string:
                line += '?%s' % filter_string
            lines.append(line)

        return "\n".join(lines)
def get_url_handle(url):
    """
    Open the url using urllib2.urlopen. If the url is a filepath
    transform it into a file url.
    """
    try:
        try:
            try:
                handle = urlopen(url)
            except (URLError, OSError):
                (scheme, netloc, path, params, query,
                        fragment) = urlparse(url)
                path = quote(path)
                newurl = urlunparse((scheme, netloc, path,
                    params, query, fragment))
                handle = urlopen(newurl)
        except ValueError:
            # If ValueError happens again we want it to raise
            url = 'file://' + os.path.abspath(url)
            handle = urlopen(url)
        return url, handle
    except HTTPError as exc:
        raise ValueError('%s: %s' % (exc, url))
def uri(name):
    """URI escape a name."""
    return quote(name.encode('utf-8'), safe='')
Пример #22
0
def encode_name(name):
    """
    Encode a unicode value as utf-8 and then URL encode that
    string. Use for entity titles in URLs.
    """
    return quote(name.encode('utf-8'), safe=".!~*'()")
Пример #23
0
def encode_name(name):
    """
    Like the encode_name found in tiddlyweb, but does not escape #.
    """
    return quote(name.encode('utf-8'), safe=".!~*'()#")
Пример #24
0
def policy_mgr(environ, start_repsonse):
    """
    Redirect to the policy manager for this tank.
    """
    tank_name = get_route_value(environ, 'bag_name')
    raise HTTP302('/policymgr#/%s' % quote(tank_name, safe=''))
Пример #25
0
def encode_name(name):
    """
    Encode a unicode value as utf-8 and then URL encode that
    string. Use for entity titles in URLs.
    """
    return quote(name.encode('utf-8'), safe=".!~*'()")