Example #1
0
 def handle_puzzlelist(self):
     puzzles = {
         "__devel__": [[0, ""]],
     }
     for p in self.server.args["puzzles_dir"].glob("*"):
         if not p.is_dir() or p.match(".*"):
             continue
         catName = p.parts[-1]
         cat = moth.Category(str(p), self.seed)
         puzzles[catName] = [[i, str(i)] for i in cat.pointvals()]
         puzzles[catName].append([0, ""])
     if len(puzzles) <= 1:
         logging.warning("No directories found matching {}/*".format(
             self.server.args["puzzles_dir"]))
     self.send_response(200)
     self.send_header("Content-Type", "application/json")
     self.end_headers()
     self.wfile.write(json.dumps(puzzles).encode("utf-8"))
Example #2
0
def package(categoryname, categorydir, seed):
    zfraw = io.BytesIO()
    zf = zipfile.ZipFile(zfraw, 'x')
    zf.writestr("category_seed.txt", str(seed))

    cat = moth.Category(categorydir, seed)
    mapping = {}
    answers = {}
    summary = {}
    for puzzle in cat:
        logging.info("Processing point value {}".format(puzzle.points))

        hashmap = hashlib.sha1(str(seed).encode('utf-8'))
        hashmap.update(str(puzzle.points).encode('utf-8'))
        puzzlehash = hashmap.hexdigest()

        mapping[puzzle.points] = puzzlehash
        answers[puzzle.points] = puzzle.answers
        summary[puzzle.points] = puzzle.summary

        puzzledir = os.path.join("content", puzzlehash)
        for fn, f in puzzle.files.items():
            payload = f.stream.read()
            zf.writestr(os.path.join(puzzledir, fn), payload)

        obj = puzzle.package()
        zf.writestr(os.path.join(puzzledir, 'puzzle.json'), json.dumps(obj))

    write_kv_pairs(zf, 'map.txt', mapping)
    write_kv_pairs(zf, 'answers.txt', answers)
    write_kv_pairs(zf, 'summaries.txt', summary)

    # clean up
    zf.close()
    zfraw.seek(0)
    return zfraw
Example #3
0
    def serve_puzzles(self):
        body = io.StringIO()
        path = self.path.rstrip('/')
        parts = path.split("/")
        title = None
        fpath = None
        points = None
        cat = None
        puzzle = None

        try:
            fpath = os.path.join(self.puzzles_dir, parts[2])
            points = int(parts[3])
        except:
            pass

        if fpath:
            cat = moth.Category(fpath, seed)
        if points:
            puzzle = cat.puzzle(points)

        if not cat:
            title = "Puzzle Categories"
            body.write("<ul>")
            for i in sorted(glob.glob(os.path.join(self.puzzles_dir, "*",
                                                   ""))):
                bn = os.path.basename(i.strip('/\\'))
                body.write(
                    '<li><a href="/puzzles/{}">puzzles/{}/</a></li>'.format(
                        bn, bn))
            body.write("</ul>")
        elif not puzzle:
            # List all point values in a category
            title = "Puzzles in category `{}`".format(parts[2])
            body.write("<ul>")
            for points in cat.pointvals():
                body.write(
                    '<li><a href="/puzzles/{cat}/{points}/">puzzles/{cat}/{points}/</a></li>'
                    .format(cat=parts[2], points=points))
            body.write("</ul>")
        elif len(parts) == 4:
            # Serve up a puzzle
            title = "{} puzzle {}".format(parts[2], parts[3])
            body.write("<h2>Body</h2>")
            body.write(puzzle.html_body())
            body.write("<h2>Files</h2>")
            body.write("<ul>")
            for name, puzzlefile in sorted(puzzle.files.items()):
                if puzzlefile.visible:
                    visibility = 'listed as a generated file'
                else:
                    visibility = 'unlisted'
                body.write(
                    '<li><a href="/puzzles/{cat}/{points}/{filename}">{filename}</a> ({visibility})</li>'
                    .format(cat=parts[2],
                            points=puzzle.points,
                            filename=name,
                            visibility=visibility))
            body.write("</ul>")
            body.write("<h2>Answers</h2>")
            body.write("<ul>")
            assert puzzle.answers, 'No answers defined'
            for a in puzzle.answers:
                body.write("<li><code>{}</code></li>".format(html.escape(a)))
            body.write("</ul>")
            body.write("<h2>Authors</h2><p>{}</p>".format(', '.join(
                puzzle.get_authors())))
            body.write("<h2>Summary</h2><p>{}</p>".format(puzzle.summary))
            if puzzle.logs:
                body.write("<h2>Debug Log</h2>")
                body.write('<ul class="log">')
                for l in puzzle.logs:
                    body.write("<li>{}</li>".format(html.escape(l)))
                body.write("</ul>")
        elif len(parts) == 5:
            # Serve up a puzzle file
            try:
                pfile = puzzle.files[parts[4]]
            except KeyError:
                self.send_error(
                    HTTPStatus.NOT_FOUND,
                    "File not found. Did you add it to the Files: header or puzzle.add_stream?"
                )
                return
            ctype = self.guess_type(pfile.name)
            self.send_response(HTTPStatus.OK)
            self.send_header("Content-Type", ctype)
            self.end_headers()
            shutil.copyfileobj(pfile.stream, self.wfile)
            return

        payload = page(title, body.getvalue()).encode('utf-8')
        self.send_response(HTTPStatus.OK)
        self.send_header("Content-Type", "text/html; charset=utf-8")
        self.send_header("Content-Length", len(payload))
        self.end_headers()
        self.wfile.write(payload)
Example #4
0
def build_category(categorydir, outdir):
    zipfileraw = tempfile.NamedTemporaryFile(delete=False)
    zf = zipfile.ZipFile(zipfileraw, 'x')

    category_seed = binascii.b2a_hex(os.urandom(20))
    puzzles_dict = {}
    secrets = {}

    categoryname = os.path.basename(categorydir.strip(os.sep))
    seedfn = os.path.join("category_seed.txt")
    zipfilename = os.path.join(outdir, "%s.zip" % categoryname)
    logging.info("Building {} from {}".format(zipfilename, categorydir))

    if os.path.exists(zipfilename):
        # open and gather some state
        existing = zipfile.ZipFile(zipfilename, 'r')
        try:
            category_seed = existing.open(seedfn).read().strip()
        except:
            pass
        existing.close()
    logging.debug("Using PRNG seed {}".format(category_seed))

    zf.writestr(seedfn, category_seed)

    cat = moth.Category(categorydir, category_seed)
    mapping = {}
    answers = {}
    summary = {}
    for puzzle in cat:
        logging.info("Processing point value {}".format(puzzle.points))

        hashmap = hashlib.sha1(category_seed)
        hashmap.update(str(puzzle.points).encode('utf-8'))
        puzzlehash = hashmap.hexdigest()
        
        mapping[puzzle.points] = puzzlehash
        answers[puzzle.points] = puzzle.answers
        summary[puzzle.points] = puzzle.summary

        puzzledir = os.path.join('content', puzzlehash)
        files = []
        for fn, f in puzzle.files.items():
            if f.visible:
                files.append(fn)
            payload = f.stream.read()
            zf.writestr(os.path.join(puzzledir, fn), payload)

        puzzledict = {
            'authors': puzzle.authors,
            'hashes': puzzle.hashes(),
            'files': files,
            'body': puzzle.html_body(),
        }
        puzzlejson = json.dumps(puzzledict)
        zf.writestr(os.path.join(puzzledir, 'puzzle.json'), puzzlejson)
        generate_html(zf, puzzle, puzzledir, categoryname, puzzle.points, puzzle.get_authors(), files)

    write_kv_pairs(zf, 'map.txt', mapping)
    write_kv_pairs(zf, 'answers.txt', answers)
    write_kv_pairs(zf, 'summaries.txt', summary)

    # clean up
    zf.close()

    shutil.move(zipfileraw.name, zipfilename)
Example #5
0
    def serve_puzzles(self):
        body = []
        path = self.path.rstrip('/')
        parts = path.split("/")
        #raise ValueError(parts)
        if len(parts) < 3:
            # List all categories
            body.append("# Puzzle Categories")
            for i in glob.glob(os.path.join("puzzles", "*", "")):
                body.append("* [{}](/{})".format(i, i))
            self.serve_md('\n'.join(body))
            return

        fpath = os.path.join("puzzles", parts[2])
        cat = moth.Category(fpath, seed)
        if len(parts) == 3:
            # List all point values in a category
            body.append("# Puzzles in category `{}`".format(parts[2]))
            for points in cat.pointvals:
                body.append(
                    "* [puzzles/{cat}/{points}](/puzzles/{cat}/{points}/)".
                    format(cat=parts[2], points=points))
            self.serve_md('\n'.join(body))
            return

        pzl = cat.puzzle(int(parts[3]))
        if len(parts) == 4:
            body.append("# {} puzzle {}".format(parts[2], parts[3]))
            body.append("* Author: `{}`".format(pzl['author']))
            body.append("* Summary: `{}`".format(pzl['summary']))
            body.append('')
            body.append("## Body")
            body.append(pzl.body)
            body.append("## Answers")
            for a in pzl['answer']:
                body.append("* `{}`".format(a))
            body.append("")
            body.append("## Files")
            for pzl_file in pzl['files']:
                body.append(
                    "* [puzzles/{cat}/{points}/{filename}]({filename})".format(
                        cat=parts[2], points=pzl.points, filename=pzl_file))

            if len(pzl.logs) > 0:
                body.extend(["", "## Logs"])
                body.append("* [Full Log File](_logs)".format(
                    cat=parts[2], points=pzl.points))
                body.extend(["", "### Logs Head"])
                for log in pzl.logs[:10]:
                    body.append("* `{}`".format(log))
                body.extend(["", "### Logs Tail"])
                for log in pzl.logs[-10:]:
                    body.append("* `{}`".format(log))
            self.serve_md('\n'.join(body))
            return
        elif len(parts) == 5:
            if parts[4] == '_logs':
                self.serve_puzzle_logs(pzl.logs)
            else:
                try:
                    self.serve_puzzle_file(pzl['files'][parts[4]])
                except KeyError:
                    self.send_error(HTTPStatus.NOT_FOUND, "File not found")
                    return
        else:
            body.append("# Not Implemented Yet")
            self.serve_md('\n'.join(body))