Add DeveloperKey model

We're starting to see developers use subkeys of their primary key to
sign packages, which we aren't handling well in the web interface. These
subkeys show up as unknown, which isn't strictly true. Start the process
of being able to handle these keys by adding a model that will store all
known keys and subkeys and the relationships among them, as well as
which developer owns each.

Signed-off-by: Dan McGee <dan@archlinux.org>
This commit is contained in:
Dan McGee 2013-02-03 13:55:25 -06:00
parent 844ed81093
commit 9da8a63dd4
3 changed files with 150 additions and 3 deletions

View File

@ -2,7 +2,7 @@
from django.contrib.auth.admin import UserAdmin from django.contrib.auth.admin import UserAdmin
from django.contrib.auth.models import User from django.contrib.auth.models import User
from .models import UserProfile, MasterKey, PGPSignature from .models import UserProfile, MasterKey, DeveloperKey, PGPSignature
class UserProfileInline(admin.StackedInline): class UserProfileInline(admin.StackedInline):
@ -17,7 +17,14 @@ class UserProfileAdmin(UserAdmin):
class MasterKeyAdmin(admin.ModelAdmin): class MasterKeyAdmin(admin.ModelAdmin):
list_display = ('pgp_key', 'owner', 'created', 'revoker', 'revoked') list_display = ('pgp_key', 'owner', 'created', 'revoker', 'revoked')
search_fields = ('pgp_key', 'owner', 'revoker') search_fields = ('pgp_key', 'owner__username', 'revoker__username')
date_hierarchy = 'created'
class DeveloperKeyAdmin(admin.ModelAdmin):
list_display = ('key', 'parent', 'owner', 'created', 'expires', 'revoked')
search_fields = ('key', 'owner__username')
list_filter = ('owner',)
date_hierarchy = 'created' date_hierarchy = 'created'
@ -32,6 +39,7 @@ class PGPSignatureAdmin(admin.ModelAdmin):
admin.site.register(User, UserProfileAdmin) admin.site.register(User, UserProfileAdmin)
admin.site.register(MasterKey, MasterKeyAdmin) admin.site.register(MasterKey, MasterKeyAdmin)
admin.site.register(DeveloperKey, DeveloperKeyAdmin)
admin.site.register(PGPSignature, PGPSignatureAdmin) admin.site.register(PGPSignature, PGPSignatureAdmin)
# vim: set ts=4 sw=4 et: # vim: set ts=4 sw=4 et:

View File

@ -0,0 +1,126 @@
# -*- coding: utf-8 -*-
from south.db import db
from south.v2 import SchemaMigration
from django.db import models
class Migration(SchemaMigration):
def forwards(self, orm):
db.create_table('devel_developerkey', (
('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
('owner', self.gf('django.db.models.fields.related.ForeignKey')(related_name='all_keys', null=True, to=orm['auth.User'])),
('key', self.gf('devel.fields.PGPKeyField')(unique=True, max_length=40)),
('created', self.gf('django.db.models.fields.DateTimeField')()),
('expires', self.gf('django.db.models.fields.DateTimeField')(null=True, blank=True)),
('revoked', self.gf('django.db.models.fields.DateTimeField')(null=True, blank=True)),
('parent', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['devel.DeveloperKey'], null=True, on_delete=models.SET_NULL)),
))
db.send_create_signal('devel', ['DeveloperKey'])
def backwards(self, orm):
db.delete_table('devel_developerkey')
models = {
'auth.group': {
'Meta': {'object_name': 'Group'},
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}),
'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'})
},
'auth.permission': {
'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", 'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'},
'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
},
'auth.user': {
'Meta': {'object_name': 'User'},
'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),
'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}),
'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'})
},
'contenttypes.contenttype': {
'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},
'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
},
'devel.developerkey': {
'Meta': {'object_name': 'DeveloperKey'},
'created': ('django.db.models.fields.DateTimeField', [], {}),
'expires': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'key': ('devel.fields.PGPKeyField', [], {'unique': 'True', 'max_length': '40'}),
'owner': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'all_keys'", 'null': 'True', 'to': "orm['auth.User']"}),
'parent': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['devel.DeveloperKey']", 'null': 'True', 'on_delete': 'models.SET_NULL'}),
'revoked': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'})
},
'devel.masterkey': {
'Meta': {'ordering': "('created',)", 'object_name': 'MasterKey'},
'created': ('django.db.models.fields.DateField', [], {}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'owner': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'masterkey_owner'", 'to': "orm['auth.User']"}),
'pgp_key': ('devel.fields.PGPKeyField', [], {'max_length': '40'}),
'revoked': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
'revoker': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'masterkey_revoker'", 'to': "orm['auth.User']"})
},
'devel.pgpsignature': {
'Meta': {'ordering': "('signer', 'signee')", 'object_name': 'PGPSignature'},
'created': ('django.db.models.fields.DateField', [], {}),
'expires': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'signee': ('devel.fields.PGPKeyField', [], {'max_length': '40'}),
'signer': ('devel.fields.PGPKeyField', [], {'max_length': '40'}),
'valid': ('django.db.models.fields.BooleanField', [], {'default': 'True'})
},
'devel.userprofile': {
'Meta': {'object_name': 'UserProfile', 'db_table': "'user_profiles'"},
'alias': ('django.db.models.fields.CharField', [], {'max_length': '50'}),
'allowed_repos': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['main.Repo']", 'symmetrical': 'False', 'blank': 'True'}),
'country': ('django_countries.fields.CountryField', [], {'max_length': '2', 'blank': 'True'}),
'favorite_distros': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'interests': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}),
'languages': ('django.db.models.fields.CharField', [], {'max_length': '50', 'null': 'True', 'blank': 'True'}),
'last_modified': ('django.db.models.fields.DateTimeField', [], {}),
'latin_name': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}),
'location': ('django.db.models.fields.CharField', [], {'max_length': '50', 'null': 'True', 'blank': 'True'}),
'notify': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
'occupation': ('django.db.models.fields.CharField', [], {'max_length': '50', 'null': 'True', 'blank': 'True'}),
'other_contact': ('django.db.models.fields.CharField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}),
'pgp_key': ('devel.fields.PGPKeyField', [], {'max_length': '40', 'null': 'True', 'blank': 'True'}),
'picture': ('django.db.models.fields.files.FileField', [], {'default': "'devs/silhouette.png'", 'max_length': '100'}),
'public_email': ('django.db.models.fields.CharField', [], {'max_length': '50'}),
'roles': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}),
'time_zone': ('django.db.models.fields.CharField', [], {'default': "'UTC'", 'max_length': '100'}),
'user': ('django.db.models.fields.related.OneToOneField', [], {'related_name': "'userprofile'", 'unique': 'True', 'to': "orm['auth.User']"}),
'website': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
'yob': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'})
},
'main.repo': {
'Meta': {'ordering': "('name',)", 'object_name': 'Repo', 'db_table': "'repos'"},
'bugs_category': ('django.db.models.fields.SmallIntegerField', [], {'default': '2'}),
'bugs_project': ('django.db.models.fields.SmallIntegerField', [], {'default': '1'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}),
'staging': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'svn_root': ('django.db.models.fields.CharField', [], {'max_length': '64'}),
'testing': ('django.db.models.fields.BooleanField', [], {'default': 'False'})
}
}
complete_apps = ['devel']

View File

@ -68,7 +68,6 @@ def get_absolute_url(self):
return '/%s/#%s' % (prefix, self.user.username) return '/%s/#%s' % (prefix, self.user.username)
class MasterKey(models.Model): class MasterKey(models.Model):
owner = models.ForeignKey(User, related_name='masterkey_owner', owner = models.ForeignKey(User, related_name='masterkey_owner',
help_text="The developer holding this master key") help_text="The developer holding this master key")
@ -88,6 +87,20 @@ def __unicode__(self):
self.owner.get_full_name(), self.created) self.owner.get_full_name(), self.created)
class DeveloperKey(models.Model):
owner = models.ForeignKey(User, related_name='all_keys', null=True,
help_text="The developer this key belongs to")
key = PGPKeyField(max_length=40, verbose_name="PGP key fingerprint",
unique=True)
created = models.DateTimeField()
expires = models.DateTimeField(null=True, blank=True)
revoked = models.DateTimeField(null=True, blank=True)
parent = models.ForeignKey('self', null=True, on_delete=models.SET_NULL)
def __unicode__(self):
return self.key
class PGPSignature(models.Model): class PGPSignature(models.Model):
signer = PGPKeyField(max_length=40, verbose_name="Signer key fingerprint") signer = PGPKeyField(max_length=40, verbose_name="Signer key fingerprint")
signee = PGPKeyField(max_length=40, verbose_name="Signee key fingerprint") signee = PGPKeyField(max_length=40, verbose_name="Signee key fingerprint")