From 92e9b7cb3c411097c5e3289fa54f65143859d0d8 Mon Sep 17 00:00:00 2001 From: eric Date: Tue, 4 Aug 2015 12:02:06 -0400 Subject: [PATCH] allow only approved repos --- admin.py | 5 +++++ api/migrations/0001_initial.py | 34 ++++++++++++++++++++++++++++++++++ api/migrations/__init__.py | 0 api/models.py | 31 +++++++++++++++++++++++++++++++ api/tests.py | 19 +++++++++++++++++++ api/views.py | 4 ++++ 6 files changed, 93 insertions(+) create mode 100644 api/migrations/0001_initial.py create mode 100644 api/migrations/__init__.py diff --git a/admin.py b/admin.py index ad0dbf9a..105b79a1 100644 --- a/admin.py +++ b/admin.py @@ -36,6 +36,7 @@ regluit imports from regluit import payment from regluit.core import models from regluit.marc.models import MARCRecord +from regluit.api.models import AllowedRepo from regluit.core.lookups import ( PublisherNameLookup, WorkLookup, @@ -233,6 +234,9 @@ class MARCRecordAdmin(ModelAdmin): date_hierarchy = 'created' form = MARCRecordAdminForm +class AllowedRepoAdmin(ModelAdmin): + list_display = ('org', 'repo_name') + admin_site = RegluitAdmin("Admin") admin_site.register(User, UserAdmin) @@ -258,6 +262,7 @@ admin_site.register(models.CeleryTask, CeleryTaskAdmin) admin_site.register(models.Press, PressAdmin) admin_site.register(models.Gift, GiftAdmin) admin_site.register(MARCRecord, MARCRecordAdmin) +admin_site.register(AllowedRepo, AllowedRepoAdmin) admin_site.register(models.Relation, RelationAdmin) # payments diff --git a/api/migrations/0001_initial.py b/api/migrations/0001_initial.py new file mode 100644 index 00000000..773a6325 --- /dev/null +++ b/api/migrations/0001_initial.py @@ -0,0 +1,34 @@ +# -*- coding: utf-8 -*- +import datetime +from south.db import db +from south.v2 import SchemaMigration +from django.db import models + + +class Migration(SchemaMigration): + + def forwards(self, orm): + # Adding model 'AllowedRepo' + db.create_table('api_allowedrepo', ( + ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)), + ('org', self.gf('django.db.models.fields.CharField')(max_length=39)), + ('repo_name', self.gf('django.db.models.fields.CharField')(max_length=100)), + )) + db.send_create_signal('api', ['AllowedRepo']) + + + def backwards(self, orm): + # Deleting model 'AllowedRepo' + db.delete_table('api_allowedrepo') + + + models = { + 'api.allowedrepo': { + 'Meta': {'object_name': 'AllowedRepo'}, + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'org': ('django.db.models.fields.CharField', [], {'max_length': '39'}), + 'repo_name': ('django.db.models.fields.CharField', [], {'max_length': '100'}) + } + } + + complete_apps = ['api'] \ No newline at end of file diff --git a/api/migrations/__init__.py b/api/migrations/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/api/models.py b/api/models.py index e69de29b..8d20ce74 100644 --- a/api/models.py +++ b/api/models.py @@ -0,0 +1,31 @@ +from django.db import models + + + +#https://github.com/GITenberg/Adventures-of-Huckleberry-Finn_76/raw/master/metadata.yaml + +def repo_allowed(repo_url): + if not repo_url.startswith('https://github.com/'): + return (False, "repo url must start with 'https://github.com/'") + try: + (org,repo_name,raw,branch,filename) = repo_url[19:].split('/') + except ValueError: + return (False, "repo url must be well formed, metadata at top repo level") + if not raw == 'raw': + return (False, "repo url must point at 'raw' file") + if not filename == 'metadata.yaml': + return (False, "repo filename must be 'metadata.yaml'") + if not branch == 'master': + return (False, "repo branch must be 'master'") + allowed_repos = AllowedRepo.objects.filter(org=org) + for allowed_repo in allowed_repos: + if allowed_repo.repo_name == '*': + return (True, '*') + if allowed_repo.repo_name == repo_name: + return (True, '*') + return (False, "no allowed repos in that org") + +class AllowedRepo(models.Model): + org = models.CharField(max_length=39) + repo_name = models.CharField(max_length=100) + \ No newline at end of file diff --git a/api/tests.py b/api/tests.py index 5a671945..b3076553 100755 --- a/api/tests.py +++ b/api/tests.py @@ -18,6 +18,7 @@ import regluit.core.isbn from regluit.core import bookloader, models from regluit.utils.localdatetime import now +from regluit.api import models as apimodels class ApiTests(TestCase): work_id=None @@ -125,3 +126,21 @@ class ApiTests(TestCase): r = self.client.get('/api/widget/%s/'%self.work_id) self.assertEqual(r.status_code, 200) +class AllowedRepoTests(TestCase): + def setUp(self): + apimodels.AllowedRepo.objects.create(org='test',repo_name='test') + apimodels.AllowedRepo.objects.create(org='star',repo_name='*') + + def test_urls(self): + #good + self.assertTrue(apimodels.repo_allowed('https://github.com/test/test/raw/master/metadata.yaml')[0]) + self.assertTrue(apimodels.repo_allowed('https://github.com/star/test/raw/master/metadata.yaml')[0]) + # bad urls + self.assertFalse(apimodels.repo_allowed('auhf8peargp8ge')[0]) + self.assertFalse(apimodels.repo_allowed('')[0]) + self.assertFalse(apimodels.repo_allowed('http://github.com/test/test/raw/master/metadata.yaml')[0]) + self.assertFalse(apimodels.repo_allowed('https://github.com/test/test/raw/master/samples/metadata.yaml')[0]) + self.assertFalse(apimodels.repo_allowed('https://github.com/test/test/raw/branch/metadata.yaml')[0]) + self.assertFalse(apimodels.repo_allowed('https://github.com/test/test/master/metadata.yaml')[0]) + self.assertFalse(apimodels.repo_allowed('https://github.com/test/test/raw/master/metadata.json')[0]) + diff --git a/api/views.py b/api/views.py index 2868513b..6ed2ff18 100755 --- a/api/views.py +++ b/api/views.py @@ -17,6 +17,7 @@ from django.http import ( import regluit.core.isbn from regluit.core.bookloader import load_from_yaml from regluit.api import opds +from regluit.api.models import repo_allowed from regluit.core import models @@ -70,6 +71,9 @@ def load_yaml(request): repo_url = request.POST.get('repo_url', None) if not repo_url: return HttpResponse('needs repo_url') + (allowed,reason) =repo_allowed(repo_url) + if not allowed: + return HttpResponse('repo_url not allowed: '+reason) try: work_id = load_from_yaml(repo_url) return HttpResponseRedirect(reverse('work', args=[work_id]))