##// END OF EJS Templates
Added signatures to the GET response. Added a view to get a full post response for one post. Don't show post key as it is present in the XML post view. Changed key display format
neko259 -
r837:fbeaaa16 decentral
parent child Browse files
Show More
@@ -12,7 +12,7 b' from django.utils import timezone'
12 12
13 13 from markupfield.fields import MarkupField
14 14
15 from boards.models import PostImage, KeyPair, GlobalId
15 from boards.models import PostImage, KeyPair, GlobalId, Signature
16 16 from boards.models.base import Viewable
17 17 from boards.models.thread import Thread
18 18 from boards import utils
@@ -54,6 +54,8 b" TAG_PUB_TIME = 'pub-time'"
54 54 TAG_EDIT_TIME = 'edit-time'
55 55 TAG_PREVIOUS = 'previous'
56 56 TAG_NEXT = 'next'
57 TAG_SIGNATURES = 'signatures'
58 TAG_SIGNATURE = 'signature'
57 59
58 60 TYPE_GET = 'get'
59 61
@@ -61,6 +63,8 b" ATTR_VERSION = 'version'"
61 63 ATTR_TYPE = 'type'
62 64 ATTR_NAME = 'name'
63 65 ATTR_REF_ID = 'ref-id'
66 ATTR_MODEL_REF = 'model-ref'
67 ATTR_VALUE = 'value'
64 68
65 69 STATUS_SUCCESS = 'success'
66 70
@@ -190,7 +194,6 b' class PostManager(models.Manager):'
190 194 cache.set(cache_key, ppd)
191 195 return ppd
192 196
193
194 197 def generate_request_get(self, model_list: list):
195 198 """
196 199 Form a get request from a list of ModelId objects.
@@ -217,13 +220,13 b' class PostManager(models.Manager):'
217 220 status.text = STATUS_SUCCESS
218 221
219 222 models = et.SubElement(response, TAG_MODELS)
223 signatures = {}
220 224
221 225 ref_id = 1
222 226 for post in model_list:
223 227 model = et.SubElement(models, TAG_MODEL)
224 228 model.set(ATTR_NAME, 'post')
225 229 model.set(ATTR_REF_ID, str(ref_id))
226 ref_id += 1
227 230
228 231 tag_id = et.SubElement(model, TAG_ID)
229 232 post.global_id.to_xml_element(tag_id)
@@ -252,7 +255,6 b' class PostManager(models.Manager):'
252 255 replied_post = Post.objects.get(id=id)
253 256 replied_post.global_id.to_xml_element(prev_id)
254 257
255
256 258 next_ids = post.referenced_posts.order_by('id').all()
257 259 if len(next_ids) > 0:
258 260 next_el = et.SubElement(model, TAG_NEXT)
@@ -260,6 +262,31 b' class PostManager(models.Manager):'
260 262 next_id = et.SubElement(next_el, TAG_ID)
261 263 ref_post.global_id.to_xml_element(next_id)
262 264
265 post_signatures = post.signature.all()
266 if post_signatures:
267 signatures[ref_id] = post.signatures
268 else:
269 # TODO Maybe the signature can be computed only once after
270 # the post is added? Need to add some on_save signal queue
271 # and add this there.
272 key = KeyPair.objects.get(public_key=post.global_id.key)
273 signatures[ref_id] = [Signature(
274 key_type=key.key_type,
275 key=key.public_key,
276 signature=key.sign(et.tostring(model, 'unicode')),
277 )]
278 ref_id += 1
279
280 signatures_tag = et.SubElement(response, TAG_SIGNATURES)
281 for ref_id in signatures.keys():
282 signatures = signatures[ref_id]
283
284 for signature in signatures:
285 signature_tag = et.SubElement(signatures_tag, TAG_SIGNATURE)
286 signature_tag.set(ATTR_MODEL_REF, str(ref_id))
287 signature_tag.set(ATTR_TYPE, signature.key_type)
288 signature_tag.set(ATTR_VALUE, signature.signature)
289
263 290 return et.tostring(response, 'unicode')
264 291
265 292
@@ -24,7 +24,7 b' class GlobalId(models.Model):'
24 24 local_id = models.IntegerField()
25 25
26 26 def __str__(self):
27 return '%s | %s | %d' % (self.key_type, self.key, self.local_id)
27 return '[%s][%s][%d]' % (self.key_type, self.key, self.local_id)
28 28
29 29 def to_xml_element(self, element: et.Element):
30 30 """
@@ -62,6 +62,14 b' class Signature(models.Model):'
62 62 class Meta:
63 63 app_label = 'boards'
64 64
65 def __init__(self, *args, **kwargs):
66 models.Model.__init__(self, *args, **kwargs)
67
68 if 'key' in kwargs and 'key_type' in kwargs and 'signature' in kwargs:
69 self.key_type = kwargs['key_type']
70 self.key = kwargs['key']
71 self.signature = kwargs['signature']
72
65 73 key_type = models.TextField()
66 74 key = models.TextField()
67 75 signature = models.TextField()
@@ -52,10 +52,10 b' class KeyPair(models.Model):'
52 52 primary = models.BooleanField(default=False)
53 53
54 54 def __str__(self):
55 return '%s | %s' % (self.key_type, self.public_key)
55 return '[%s][%s]' % (self.key_type, self.public_key)
56 56
57 57 def sign(self, string):
58 58 private = SigningKey.from_string(base64.b64decode(
59 59 self.private_key.encode()))
60 signature_byte = private.sign(string.encode())
61 return base64.b64encode(signature_byte)
60 signature_byte = private.sign_deterministic(string.encode())
61 return base64.b64encode(signature_byte).decode()
@@ -35,7 +35,8 b''
35 35 {% endif %}
36 36
37 37 {% if post.global_id %}
38 <span class="global-id"> {{ post.global_id }} </span>
38 <a class="global-id" href="
39 {% url 'post_sync_data' post.id %}"> [RAW] </a>
39 40 {% endif %}
40 41
41 42 {% if moderator %}
@@ -1,3 +1,4 b''
1 from base64 import b64encode
1 2 import logging
2 3
3 4 from django.test import TestCase
@@ -38,11 +39,15 b' class KeyTest(TestCase):'
38 39 request = Post.objects.generate_request_get([post])
39 40 logger.debug(request)
40 41
42 key = KeyPair.objects.get(primary=True)
41 43 self.assertTrue('<request type="get" version="1.0">'
42 44 '<model name="post" version="1.0">'
43 '<id key="pubkey" local-id="1" type="test_key_type" />'
45 '<id key="%s" local-id="1" type="%s" />'
44 46 '</model>'
45 '</request>' in request,
47 '</request>' % (
48 key.public_key,
49 key.key_type,
50 ) in request,
46 51 'Wrong XML generated for the GET request.')
47 52
48 53 def test_response_get(self):
@@ -58,38 +63,41 b' class KeyTest(TestCase):'
58 63 response = Post.objects.generate_response_get([reply_post])
59 64 logger.debug(response)
60 65
61 self.assertTrue('<response>'
62 '<status>success</status>'
66 key = KeyPair.objects.get(primary=True)
67 self.assertTrue('<status>success</status>'
63 68 '<models>'
64 69 '<model name="post" ref-id="1">'
65 '<id key="pubkey" local-id="%d" type="test_key_type" />'
70 '<id key="%s" local-id="%d" type="%s" />'
66 71 '<title>test_title</title>'
67 72 '<text>[post]%d[/post]</text>'
68 73 '<thread>%d</thread>'
69 74 '<pub-time>%s</pub-time>'
70 75 '<edit-time>%s</edit-time>'
71 76 '<previous>'
72 '<id key="pubkey" local-id="%d" type="test_key_type" />'
77 '<id key="%s" local-id="%d" type="%s" />'
73 78 '</previous>'
74 79 '<next>'
75 '<id key="pubkey" local-id="%d" type="test_key_type" />'
80 '<id key="%s" local-id="%d" type="%s" />'
76 81 '</next>'
77 82 '</model>'
78 '</models>'
79 '</response>' % (
83 '</models>' % (
84 key.public_key,
80 85 reply_post.id,
86 key.key_type,
81 87 post.id,
82 88 post.id,
83 89 str(reply_post.get_edit_time_epoch()),
84 90 str(reply_post.get_pub_time_epoch()),
91 key.public_key,
85 92 post.id,
93 key.key_type,
94 key.public_key,
86 95 reply_reply_post.id,
96 key.key_type,
87 97 ) in response,
88 98 'Wrong XML generated for the GET response.')
89 99
90 100 def _create_post_with_key(self):
91 key = KeyPair(public_key='pubkey', private_key='privkey',
92 key_type='test_key_type', primary=True)
93 key.save()
101 KeyPair.objects.generate_key(primary=True)
94 102
95 103 return Post.objects.create_post(title='test_title', text='test_text')
@@ -14,10 +14,7 b' class SyncTest(TestCase):'
14 14 Forms a GET request of a post and checks the response.
15 15 """
16 16
17 key = KeyPair(public_key='pubkey', private_key='privkey',
18 key_type='test_key_type', primary=True)
19 key.save()
20
17 KeyPair.objects.generate_key(primary=True)
21 18 post = Post.objects.create_post(title='test_title', text='test_text')
22 19
23 20 request = MockRequest()
@@ -32,7 +29,6 b' class SyncTest(TestCase):'
32 29 )
33 30
34 31 self.assertTrue(
35 '<response>'
36 32 '<status>success</status>'
37 33 '<models>'
38 34 '<model name="post" ref-id="1">'
@@ -42,8 +38,7 b' class SyncTest(TestCase):'
42 38 '<pub-time>%d</pub-time>'
43 39 '<edit-time>%d</edit-time>'
44 40 '</model>'
45 '</models>'
46 '</response>' % (
41 '</models>' % (
47 42 post.global_id.key,
48 43 post.id,
49 44 post.global_id.key_type,
@@ -11,6 +11,7 b' from boards.views.search import BoardSea'
11 11 from boards.views.static import StaticPageView
12 12 from boards.views.post_admin import PostAdminView
13 13 from boards.views.preview import PostPreviewView
14 from boards.views.sync import get_post_sync_data
14 15
15 16 js_info_dict = {
16 17 'packages': ('boards',),
@@ -78,6 +79,9 b" urlpatterns = patterns('',"
78 79 url(r'^search/$', BoardSearchView.as_view(), name='search'),
79 80
80 81 # Post preview
81 url(r'^preview/$', PostPreviewView.as_view(), name='preview')
82 url(r'^preview/$', PostPreviewView.as_view(), name='preview'),
83
84 url(r'^post_xml/(?P<post_id>\d+)$', get_post_sync_data,
85 name='post_sync_data'),
82 86
83 87 )
@@ -1,5 +1,5 b''
1 1 import xml.etree.ElementTree as et
2 from django.http import HttpResponse
2 from django.http import HttpResponse, Http404
3 3 from boards.models import GlobalId, Post
4 4
5 5
@@ -30,4 +30,20 b' def respond_get(request):'
30 30
31 31 response_xml = Post.objects.generate_response_get(posts)
32 32
33 return HttpResponse(content=response_xml) No newline at end of file
33 return HttpResponse(content=response_xml)
34
35
36 def get_post_sync_data(request, post_id):
37 try:
38 post = Post.objects.get(id=post_id)
39 except Post.DoesNotExist:
40 raise Http404()
41
42 content = 'Global ID: %s\n\nXML: %s' \
43 % (post.global_id, Post.objects.generate_response_get([post]))
44
45
46 return HttpResponse(
47 content_type='text/plain',
48 content=content,
49 ) No newline at end of file
General Comments 0
You need to be logged in to leave comments. Login now