def export(self, export_dir, include_disabled): '''Exports challenge Creates an archive containing all of the challenge "exportable" files. ''' if not self.is_standalone: app_log.warning(f"challenge ignored (not standalone): {self.slug}.") return {'ignored': True} if not include_disabled and not self.enabled: app_log.warning(f"challenge ignored (disabled): {self.slug}.") return {'ignored': True} app_log.info(f"exporting {self.slug}...") archive_name = f'{self.slug}.tgz' archive_path = export_dir.joinpath(archive_name) with tarfile.open(str(archive_path), 'w:gz') as arch: for entry in self.exportable(): arch.add(entry.path, arcname=entry.name) checksum_name = f'{archive_name}.sha256' checksum_path = export_dir.joinpath(checksum_name) archive_hash = hash_file(archive_path) checksum_path.write_text(f'{archive_hash} {archive_name}\n') app_log.info("done.") return { 'archive_path': archive_path, 'checksum_path': checksum_path }
async def _run(self, script, dev, timeout): '''Runs a script as an asynchronous subprocess ''' script_path = Path(script) script_parents = script_path.parents script = f'./{script_path.name}' if script_path.is_absolute(): cwd = script_parents[0] else: cwd = self.path if len(script_parents) > 1: cwd /= script_parents[0] app_log.info(f"running {script_path.name} within {cwd}.") if dev: proc = await create_subprocess_exec(script, '--dev', stdout=PIPE, stderr=PIPE, cwd=str(cwd)) else: proc = await create_subprocess_exec(script, stdout=PIPE, stderr=PIPE, cwd=str(cwd)) rcode = -1 stdout = None stderr = None exception = None try: stdout, stderr = await wait_for(proc.communicate(), timeout=timeout) rcode = proc.returncode except TimeoutError: proc.terminate() exception = 'timeout' except CalledProcessError as exc: proc.terminate() rcode = exc.returncode stdout = exc.stdout stderr = exc.stderr exception = 'called process error' except Exception as exc: exception = str(exc) if rcode == 0: app_log.info("subprocess terminated successfully.") else: app_log.warning( f"subprocess terminated unsuccessfully (rcode={rcode}).") return { 'rcode': rcode, 'stdout': stdout, 'stderr': stderr, 'exception': exception }
async def main(): '''Main function ''' app_log.info(__banner__) args = parse_args() log_enable_debug(args.debug) format_enable_colors(not args.no_color) app_log.debug(args) api = MKCTFAPI(args.repo_root) try: rcode = 0 if await args.func(api, args) else 1 except: app_log.exception("Ouch... unhandled exception... (>_<)") rcode = 2 return rcode
def main(): '''Main function ''' parser = MKCTFArgumentParser(banner=BANNER, description="An HTTP API to perform operations on a mkCTF repository.") args = parser.parse_args() api = MKCTFAPI(args.repo_dir) handler = MKCTFWebHandler(api) app = web.Application() app.add_routes([ web.get(r'/challenges', handler.enum_challenges), web.get(r'/{slug:[a-z0-9\-]+}/health', handler.challenge_status), web.post(r'/{slug:[a-z0-9\-]+}/check-flag', handler.check_challenge_flag), ]) app_log.info(f"serving from {args.repo_dir}") web.run_app(app)
def main(): '''Main function ''' app_log.info(__banner__) args = parse_args() log_enable_debug(args.debug) format_enable_colors(not args.no_color) api = MKCTFAPI(args.repo_root) handler = MKCTFWebHandler(api) app = web.Application() app.add_routes([ web.get(r'/challenges', handler.enum_challenges), web.get(r'/{slug:[a-z0-9\-]+}/status', handler.challenge_status), web.post(r'/{slug:[a-z0-9\-]+}/check-flag', handler.check_challenge_flag), ]) app_log.info(f"serving from {args.repo_root}") web.run_app(app)
def export(self, export_dir, include_disabled): '''Export the challenge Creates a gzipped tar archive containing all of the challenge "exportable" files ''' if not include_disabled and not self.conf.enabled: app_log.warning(f"export ignored {self.conf.slug} (disabled)") return app_log.info(f"exporting {self.conf.slug}...") archive_name = self.conf.static_url.split('/')[-1] if not archive_name: app_log.error( f"export ignored {self.conf.slug} (invalid/empty static_url)") app_log.error( f"running `mkctf-cli update-meta` should be enough to fix this issue." ) return archive_path = export_dir.joinpath(archive_name) checksum_file = ChecksumFile() with tarfile.open(str(archive_path), 'w:gz') as arch: for directory in self.repo.conf.directories(self.conf.category, public_only=True): dir_path = self.path.joinpath(directory) for entry in scandir(dir_path): entry_path = Path(entry.path) if entry_path.is_dir(): app_log.warning( f"export ignored {entry_path} within {self.conf.slug} (directory)" ) continue checksum_file.add(entry_path) app_log.debug(f"adding {entry_path} to archive...") arch.add(str(entry_path), arcname=entry.name) with tempfile.NamedTemporaryFile('w') as tmpfile: tmpfile.write(checksum_file.content) tmpfile.flush() app_log.debug(f"adding checksum.sha256 to archive...") arch.add(tmpfile.name, arcname='checksum.sha256') arch_checksum_file = ChecksumFile() arch_checksum_file.add(archive_path) export_dir.joinpath(f'{archive_name}.sha256').write_text( arch_checksum_file.content) return archive_path
async def export(api, args): '''Exports one or more challenges Creates one archive per challenge in a given directory ''' found = False export_dir = args.export_dir.resolve() exported = [ info for info in api.export(export_dir, tags=args.tags, categories=args.categories, slug=args.slug, include_disabled=args.include_disabled) ] export_map = {info['slug']: str(info['archive_path']) for info in exported} app_log.info("creating export.map...") with export_dir.joinpath('export.map').open('w') as fp: dump(export_map, fp) app_log.info("done.") return exported
def init(self): '''[summary] ''' if not self.initialized: wizard = RepositoryConfigurationWizard(self._general_conf) if not wizard.show(): return False self._conf = wizard.result self.path.mkdir(parents=True, exist_ok=True) self.challenges_dir.mkdir(parents=True, exist_ok=True) app_log.info("copying templates...") shutil.copytree(str(GeneralConfiguration.TEMPLATES_DIR), str(self.template_dir)) app_log.info("copying monitoring...") shutil.copytree(str(GeneralConfiguration.MONITORING_DIR), str(self.monitoring_dir)) app_log.info("saving repository configuration...") return self._save_conf() return False