예제 #1
0
 def handle(self, challenges_dir, dry_run=False, **options):
     self.challenges_dir = challenges_dir
     self.media_dir = pathlib.Path(settings.MEDIA_ROOT)
     self.dry_run = dry_run
     context = Context(elevated=True)
     old_challenges = {i.name: i for i in Challenge.get_all(context)}
     new_challenges = {}
     for path in challenges_dir.iterdir():
         if not path.is_dir() or path.name.startswith('.'):
             continue
         # noinspection PyBroadException
         try:
             challenge = self.parse_challenge(path)
         except Exception as e:
             msg = traceback.format_exception_only(type(e), e)[0].strip()
             self.stdout.write(self.style.ERROR(f'{path.name}: {msg}'))
         else:
             if challenge['enabled']:
                 new_challenges[challenge['name']] = challenge
     self.stdout.write(f'Parsed {len(new_challenges)} challenges')
     for name in new_challenges:
         if name in old_challenges:
             if not dry_run:
                 old_challenges[name].update(**new_challenges[name])
             self.stdout.write(f'{name}: ' + self.style.WARNING('updated'))
         else:
             if not dry_run:
                 Challenge.create(context, **new_challenges[name])
             self.stdout.write(f'{name}: ' + self.style.SUCCESS('created'))
     for name in old_challenges:
         if name not in new_challenges:
             if not dry_run:
                 old_challenges[name].delete()
             self.stdout.write(f'{name}: ' + self.style.NOTICE('deleted'))
예제 #2
0
 def _challenge_event(cls, old, new):
     context = Context(elevated=True)
     if old is None:
         return
     if new is None:
         models.ChallengeClear.objects.filter(challenge=old['pk']).delete()
         models.FlagClear.objects.filter(challenge=old['pk']).delete()
         models.ChallengeFirst.objects.filter(challenge=old['pk']).delete()
         models.FlagFirst.objects.filter(challenge=old['pk']).delete()
         if old['enabled']:
             cls._regen_score()
         return
     if len(new['flags']) != len(old['flags']):
         models.FlagClear.objects.filter(challenge=old['pk'],
                                         flag__gte=len(
                                             new['flags'])).delete()
         cls._regen_challenge_clear(Challenge.get(context, old['pk']))
         models.ChallengeFirst.objects.filter(challenge=old['pk']).delete()
         models.FlagFirst.objects.filter(challenge=old['pk']).delete()
         cls._refill_first()
     if not old['enabled'] and not new['enabled']:
         return
     if new['enabled'] != old['enabled']:
         cls._regen_score()
         return
     if new['category'] != old['category']:
         cls._regen_score()
         return
     old_flag_scores = [i['score'] for i in old['flags']]
     new_flag_scores = [i['score'] for i in new['flags']]
     if new_flag_scores != old_flag_scores:
         cls._regen_score()
         return
예제 #3
0
 def _regen_score(cls):
     models.Score.objects.all().delete()
     cs = {i.pk: i.json for i in Challenge.get_all(Context(elevated=True))}
     for i in models.FlagClear.objects.order_by('time').iterator():
         if cs[i.challenge]['enabled']:
             cls._add_score(i.user, i.group, i.time,
                            cs[i.challenge]['flags'][i.flag]['score'],
                            cs[i.challenge]['category'])
예제 #4
0
 def get(self, request):
     try:
         User.test_authenticated(Context.from_request(request))
     except LoginRequired:
         return redirect('hub')
     return TemplateResponse(request, 'profile.html', {
         'profile_required': User.profile_required,
     })
예제 #5
0
 def post(self, request):
     context = Context.from_request(request)
     try:
         User.test_authenticated(context)
     except LoginRequired:
         return redirect('hub')
     for pk in request.POST.getlist('terms'):
         Terms.get(context, pk=pk).agree(request.user.pk)
     return redirect('hub')
예제 #6
0
 def post(self, request):
     try:
         kwargs = json.loads(request.body)
         kwargs = {k: kwargs[k] for k in kwargs if k in User.update_fields}
         user = User.get(Context.from_request(request), request.user.pk)
         user.update(**kwargs)
         return JsonResponse({})
     except WrongFormat as e:
         return JsonResponse({'error': e.json}, status=400)
예제 #7
0
 def post(self, request):
     body = json.loads(request.body)
     method = body['method']
     args = body.get('args', {})
     try:
         method = getattr(self, f'do_{method}')
         value = method(Context.from_request(request), **args)
         return JsonResponse({'value': value})
     except Error as e:
         return JsonResponse({'error': e.json}, status=400)
예제 #8
0
 def save_user(self, request, sociallogin, form=None):
     super().save_user(request, sociallogin, form)
     user = sociallogin.user
     User.create(
         Context(elevated=True),
         group='other',
         user=user,
         email=user.email,
     )
     return user
예제 #9
0
    def initialize(self, context):
        self.context = Context(
            server=context.server,
            config=context.config,
            importer=context.modules.importer,
            request_handler=self
        )
        RepositoryMixin.initialize(self, self.context)

        self.remote_ip = self.request.headers.get('X-Forwarded-For',
                                                  self.request.headers.get('X-Real-Ip', self.request.remote_ip))
예제 #10
0
 def _add_expr(cls, expr):
     from .expr_flags import expr_flag
     if models.Expr.objects.filter(expr=expr).exists():
         return False
     for user_obj in models.User.objects.all():
         token = User.get(Context(elevated=True), user_obj.user).token
         models.ExprFlag.objects.create(
             expr=expr,
             user=user_obj.user,
             flag=expr_flag(expr, token),
         )
     return True
예제 #11
0
 def get(self, request):
     try:
         return TemplateResponse(
             request, self.template, {
                 **site.each_context(request),
                 **self.get_extra_context(Context.from_request(request)),
                 'title':
                 self.title,
             })
     except Error as e:
         messages.error(request, e.message)
         return redirect('hub')
예제 #12
0
 def _add_user(cls, user):
     from .expr_flags import expr_flag
     if models.User.objects.filter(user=user).exists():
         return False
     token = User.get(Context(elevated=True), user).token
     for expr_obj in models.Expr.objects.values('expr').distinct():
         models.ExprFlag.objects.create(
             expr=expr_obj['expr'],
             user=user,
             flag=expr_flag(expr_obj['expr'], token),
         )
     return True
예제 #13
0
def frontend(request):
    return {
        'page':
        Page.get(),
        'user_': (User.get(Context.from_request(request), request.user.pk)
                  if request.user.is_authenticated else None),
        'groups':
        User.groups,
        'debug':
        settings.DEBUG,
        'no_board_groups':
        User.no_board_groups,
    }
예제 #14
0
 def post(self, request):
     if not self.check():
         return redirect('hub')
     eligible = request.POST['eligible']
     if eligible == 'yes':
         UstcEligible.objects.create(user=request.user, eligible=True)
         user = User.get(
             Context.from_request(request).copy(elevated=True),
             request.user.pk)
         user.update(group='ustc')
     elif eligible == 'no':
         UstcEligible.objects.create(user=request.user, eligible=False)
     return redirect('hub')
예제 #15
0
 def post(self, request):
     try:
         matches = Submission.submit(Context.from_request(request),
                                     request.user.pk,
                                     request.POST['challenge'],
                                     request.POST['flag'].strip())
         if matches:
             messages.success(request, '答案正确')
         else:
             messages.error(request, '答案错误')
     except Error as e:
         messages.info(request, e.message)
     return redirect('hub')
예제 #16
0
 def login(self, **kwargs):
     account, created = Account.objects.get_or_create(
         provider=self.provider,
         identity=self.normalize_identity(),
     )
     self.on_get_account(account)
     if not account.user:
         account.user = User.create(
             Context(elevated=True),
             group=self.group,
             **kwargs,
         ).user
         account.save()
     login(self.request, account.user, self.backend)
예제 #17
0
 def get(self, request):
     context = Context.from_request(request)
     try:
         return TemplateResponse(
             request, 'board.html', {
                 'filters': {
                     'category': request.GET.get('category', None),
                     'group': request.GET.get('group', None),
                 },
                 'users':
                 {u.pk: u.display_name
                  for u in User.get_all(context)},
             })
     except Error as e:
         messages.error(request, e.message)
         return redirect('hub')
예제 #18
0
 def get(self, request):
     context = Context.from_request(request)
     try:
         return TemplateResponse(
             request, 'first.html', {
                 'filters': {
                     'group': request.GET.get('group', None),
                 },
                 'users': {u.pk: u.json
                           for u in User.get_all(context)},
                 'challenges':
                 [c.json for c in Challenge.get_enabled(context)],
             })
     except Error as e:
         messages.error(request, e.message)
         return redirect('hub')
예제 #19
0
 def _refill_first(cls):
     """尝试把 ChallengeFirst 和 FlagFirst 中的空位都填上"""
     for challenge in Challenge.get_all(Context(elevated=True)):
         for group in {None, *User.groups}.difference(
             models.ChallengeFirst.objects
             .filter(challenge=challenge.pk)
             .values_list('group', flat=True)
         ):
             try:
                 first = (
                     cls._filter_group(models.ChallengeClear.objects, group)
                     .filter(challenge=challenge.pk)
                     .earliest('time')
                 )
                 models.ChallengeFirst.objects.create(
                     challenge=challenge.pk,
                     group=group,
                     user=first.user,
                     time=first.time,
                 )
             except models.ChallengeClear.DoesNotExist:
                 pass
         for flag in range(len(challenge.flags)):
             for group in {None, *User.groups}.difference(
                 models.FlagFirst.objects
                 .filter(challenge=challenge.pk, flag=flag)
                 .values_list('group', flat=True)
             ):
                 try:
                     first = (
                         cls._filter_group(models.FlagClear.objects, group)
                         .filter(challenge=challenge.pk, flag=flag)
                         .earliest('time')
                     )
                     models.FlagFirst.objects.create(
                         challenge=challenge.pk,
                         flag=flag,
                         group=group,
                         user=first.user,
                         time=first.time,
                     )
                 except models.FlagClear.DoesNotExist:
                     pass
예제 #20
0
 def get(self, request):
     if request.user.is_authenticated:
         if Account.objects.filter(provider='ustc',
                                   user=request.user).exists():
             try:
                 request.user.ustceligible
             except UstcEligible.DoesNotExist:
                 return redirect('ustcprofile')
     context = Context.from_request(request)
     try:
         challenges = Challenge.get_enabled(context)
         challenges = {'value': [obj.json for obj in challenges]}
     except ProfileRequired as e:
         messages.info(request, e.message)
         return redirect('profile')
     except TermsRequired as e:
         messages.info(request, e.message)
         return redirect('terms')
     except Error as e:
         challenges = {'error': e.json}
     try:
         announcement = Announcement.get_latest(context).json
     except NotFound:
         announcement = None
     if request.user.is_authenticated:
         user = User.get(context, request.user.pk)
         if user.group == 'other':
             ranking = Submission.get_user_ranking(context, request.user.pk)
         else:
             ranking = Submission.get_user_ranking(context,
                                                   request.user.pk,
                                                   group=user.group)
     else:
         ranking = {}
     return TemplateResponse(
         request, 'hub.html', {
             'announcement': announcement,
             'challenges': challenges,
             'progress': Submission.get_user_progress(
                 context, request.user.pk),
             'ranking': ranking,
             'clear_count': Submission.get_clear_count(context),
         })
예제 #21
0
def set_group(apps, schema_editor):
    Submission = apps.get_model('submission', 'Submission')
    db_alias = schema_editor.connection.alias
    for obj in Submission.objects.using(db_alias).all():
        obj.group = User.get(Context(elevated=True), obj.user).group
        obj.save()
예제 #22
0
from server.context import Context
from server import di

di.cxt = Context()

from server.api import task_bp, file_bp, web_bp, user_bp, visit_bp, status_bp

app = di.cxt.app
app.register_blueprint(task_bp, url_prefix='/tasks')
app.register_blueprint(file_bp, url_prefix='/files')
app.register_blueprint(web_bp, url_prefix='/webs')
app.register_blueprint(user_bp, url_prefix='/users')
app.register_blueprint(visit_bp, url_prefix='/visits')
app.register_blueprint(status_bp, url_prefix='/status')
예제 #23
0
 def get(self, request):
     context = Context.from_request(request)
     return TemplateResponse(request, 'announcements.html', {
         'announcements': [i.json for i in Announcement.get_all(context)],
     })
예제 #24
0
def get_context(server_parameters, config, importer):
    return Context(
        server=server_parameters,
        config=config,
        importer=importer
    )
예제 #25
0
    def handle(self, fake_complex_challenges, fake_simple_challenges,
               fake_users, fake_submissions, game_started_seconds,
               **options):
        root = User.create(
            Context(elevated=True),
            group='other',
            nickname='root',
        ).user
        root.is_staff = True
        root.is_superuser = True
        root.save()
        root.refresh_from_db()
        Account.objects.create(provider='debug', identity='root', user=root)

        c1 = Challenge.create(
            Context(root),
            name='签到题',
            category='checkin',
            detail='签到题描述',
            url='https://example.com/{token}',
            prompt='flag{hackergame}',
            index=-100,
            enabled=True,
            flags=[{
                'name': '',
                'score': 10,
                'type': 'text',
                'flag': 'flag{hackergame}',
            }],
        )
        Submission.submit(Context(root), root.pk, c1.pk, 'flag{hackergame}')

        for i in range(1, fake_complex_challenges + 1):
            Challenge.create(
                Context(root),
                name=f'复杂题 {i}',
                category='complex',
                detail='<code>flag{FLAG_INDEX}</code> 或 '
                       '<code>flag{FLAG_INDEX:USER_ID}</code>',
                url='',
                prompt='flag{...}',
                index=random.randrange(100),
                enabled=random.choice((False, True, True, True, True)),
                flags=[{
                    'name': f'flag {j}',
                    'score': random.randrange(100),
                    'type': ('expr', 'text')[j % 2],
                    'flag': ("f'flag{{%s:{token.partition(\":\")[0]}}}'" % j,
                             f'flag{{{j}}}')[j % 2],
                } for j in range(random.randrange(1, 4))],
            )

        for i in range(1, fake_simple_challenges + 1):
            Challenge.create(
                Context(root),
                name=f'简单题 {i}',
                category='simple',
                detail='',
                url='',
                prompt=('flag{0}', 'flag{0:USER_ID}')[i % 2],
                index=random.randrange(100),
                enabled=random.choice((False, True, True, True, True)),
                flags=[{
                    'name': '',
                    'score': random.randrange(100),
                    'type': ('text', 'expr')[i % 2],
                    'flag': ('flag{0}',
                             "'flag{0:'+token.partition(':')[0]+'}'")[i % 2],
                }],
            )

        terms = Terms.create(Context(root), name='条款', content='1 2 3 ...',
                             enabled=True)

        now = timezone.now()
        timestamps = []
        for i in range(fake_submissions):
            delta = random.randrange(game_started_seconds)
            timestamps.append(now - timezone.timedelta(seconds=delta))
        timestamps.sort()

        Trigger.create(Context(root), time=min(timestamps), state=True)

        groups = list(set(User.groups.keys()) - {'staff', 'banned'})
        for i in range(fake_users):
            print('user', i, end='\r')
            u = User.create(
                Context(elevated=True),
                group=random.choice(groups),
                nickname='用户 ' * 8 + str(i),
                name='姓名',
                sno='PB11111111',
                tel='123456789',
                email='*****@*****.**',
                gender=random.choice(('female', 'male')),
                qq='12345',
                school='foo',
                grade='1',
            )
            Terms.get(Context(u.user), terms.pk).agree(u.pk)
            Account.objects.create(provider='debug', identity=f'{i}',
                                   user=u.user)

        users = [i.pk for i in User.get_all(Context(root))]
        challenges = [i.pk for i in Challenge.get_all(Context(root))]

        for i in range(fake_submissions):
            print('submission', i, end='\r')
            try:
                u = random.choice(users)
                c = random.choice(challenges)
                fs = len(Challenge.get(Context(root), c).flags)
                Submission.submit(
                    Context(
                        User.get(Context(root), u).user,
                        timestamps[i]
                    ), u, c, f'flag{{{random.choice(range(fs))}:{u}}}'
                )
                Submission.submit(
                    Context(
                        User.get(Context(root), u).user,
                        timestamps[i] + timezone.timedelta(seconds=20)
                    ), u, c, f'flag{{{random.choice(range(fs))}}}'
                )
            except (NotFound, SlowDown):
                pass

        Challenge.create(
            Context(root),
            name='难题',
            category='hard',
            detail='难题描述',
            url='https://example.com/{token}',
            prompt='flag{hackergame}',
            index=100,
            enabled=True,
            flags=[{
                'name': '',
                'score': 100,
                'type': 'text',
                'flag': 'flag{hackergame}',
            }],
        )
예제 #26
0
 def handle(self, *args, **options):
     context = Context(elevated=True)
     Challenge.regen_all(context)
     Submission.regen_all(context)
예제 #27
0
 def get(self, request):
     terms = Terms.get_enabled(Context.from_request(request))
     return TemplateResponse(request, 'terms.html', {'terms': terms})