Skip to content

Commit ae50635

Browse files
committed
hashing migrated to devel
1 parent f326302 commit ae50635

30 files changed

Lines changed: 522 additions & 81 deletions

backend/globaleaks/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
__version__ = '5.0.90'
1010
__license__ = 'AGPL-3.0'
1111

12-
DATABASE_VERSION = 71
12+
DATABASE_VERSION = 72
1313
FIRST_DATABASE_VERSION_SUPPORTED = 52
1414

1515
# Add new languages as they are supported here! To do this retrieve the name of

backend/globaleaks/db/migration.py

Lines changed: 43 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@
3939
Subscriber_v_68, InternalFile_v_68, ReceiverFile_v_68, Mail_v_68
4040
from globaleaks.db.migrations.update_70 import InternalTipAnswers_v_69, User_v_69
4141
from globaleaks.db.migrations.update_71 import Tenant_v_70
42+
from globaleaks.db.migrations.update_72 import Comment_v_71, InternalFile_v_71, ReceiverFile_v_71
4243

4344
from globaleaks.orm import get_engine, get_session, make_db_uri
4445
from globaleaks.models import config, Base
@@ -49,48 +50,48 @@
4950

5051

5152
migration_mapping = OrderedDict([
52-
('ArchivedSchema', [models._ArchivedSchema, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]),
53-
('AuditLog', [-1, -1, AuditLog_v_61, 0, 0, 0, 0, 0, 0, 0, models._AuditLog, 0, 0, 0, 0, 0, 0, 0, 0, 0]),
54-
('Comment', [Comment_v_64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, models._Comment, 0, 0, 0, 0, 0, 0]),
55-
('Config', [models._Config, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]),
56-
('ConfigL10N', [models._ConfigL10N, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]),
57-
('ContentForwarding', [-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, models._ContentForwarding, 0, 0]),
58-
('Context', [Context_v_61, 0, 0, 0, 0, 0, 0, 0, 0, 0, Context_v_63, 0, models._Context, 0, 0, 0, 0, 0, 0, 0]),
59-
('CustomTexts', [models._CustomTexts, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]),
60-
('EnabledLanguage', [models._EnabledLanguage, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]),
61-
('Field', [Field_v_68, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, models._Field, 0, 0]),
62-
('FieldAttr', [FieldAttr_v_52, models._FieldAttr, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]),
63-
('FieldOption', [models._FieldOption, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]),
64-
('FieldOptionTriggerField', [models._FieldOptionTriggerField, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]),
65-
('FieldOptionTriggerStep', [models._FieldOptionTriggerStep, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]),
66-
('File', [File_v_53, 0, models._File, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]),
67-
('IdentityAccessRequest', [IdentityAccessRequest_v_64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, models._IdentityAccessRequest, 0, 0, 0, 0, 0, 0]),
68-
('IdentityAccessRequestCustodian', [-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, models._IdentityAccessRequestCustodian, 0, 0, 0, 0, 0, 0]),
69-
('InternalFile', [InternalFile_v_64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, InternalFile_v_68, 0, 0, 0, models._InternalFile, 0, 0]),
70-
('InternalTip', [InternalTip_v_52, InternalTip_v_57, 0, 0, 0, 0, InternalTip_v_59, 0, InternalTip_v_63, 0, 0, 0, InternalTip_v_64, InternalTip_v_66, 0, models._InternalTip, 0, 0, 0, 0]),
71-
('InternalTipAnswers', [InternalTipAnswers_v_68, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, InternalTipAnswers_v_69, models._InternalTipAnswers, 0]),
72-
('InternalTipData', [models._InternalTipData, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]),
73-
('InternalTipForwarding', [-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, models._InternalTipForwarding, 0, 0]),
74-
('Mail', [Mail_v_68, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, models._Mail, 0, 0]),
75-
('Message', [Message_v_64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, -1, -1, -1, -1, -1, -1, -1]),
76-
('Questionnaire', [models._Questionnaire, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]),
77-
('ReceiverContext', [models._ReceiverContext, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]),
78-
('ReceiverFile', [ReceiverFile_v_57, 0, 0, 0, 0, 0, ReceiverFile_v_64, 0, 0, 0, 0, 0, 0, ReceiverFile_v_66, 0, ReceiverFile_v_68, 0, models._ReceiverFile, 0, 0]),
79-
('ReceiverTip', [ReceiverTip_v_52, ReceiverTip_v_57, 0, 0, 0, 0, ReceiverTip_v_58, ReceiverTip_v_59, ReceiverTip_v_61, 0, ReceiverTip_v_64, 0, 0, models._ReceiverTip, 0, 0, 0, 0, 0, 0]),
80-
('Redaction', [-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, Redaction_v_66, 0, models._Redaction, 0, 0, 0, 0]),
81-
('Redirect', [models._Redirect, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]),
82-
('SubmissionStatus', [SubmissionStatus_v_64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, models._SubmissionStatus, 0, 0, 0, 0, 0]),
83-
('SubmissionSubStatus', [SubmissionSubStatus_v_64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, SubmissionSubStatus_v_65, 0, models._SubmissionSubStatus, 0, 0, 0, 0]),
84-
('SubmissionStatusChange', [SubmissionStatusChange_v_54, 0, 0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1]),
85-
('Step', [models._Step, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]),
86-
('Subscriber', [Subscriber_v_52, Subscriber_v_62, 0, 0, 0, 0, 0, 0, 0, 0, 0, Subscriber_v_67, 0, 0, 0, 0, Subscriber_v_68, models._Subscriber, 0, 0]),
87-
('Tenant', [Tenant_v_52, Tenant_v_68, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, Tenant_v_70, 0, models._Tenant]),
88-
('User', [User_v_52, User_v_54, 0, User_v_56, 0, User_v_61, 0, 0, 0, 0, User_v_64, 0, 0, User_v_66, 0, User_v_68, 0, User_v_69, 0, models._User]),
89-
('UserProfile', [-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, models._UserProfile]),
90-
('UserProfilePermission', [-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, models._UserProfilePermission]),
91-
('UserProfileRole', [-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, models._UserProfileRole]),
92-
('WhistleblowerFile', [WhistleblowerFile_v_57, 0, 0, 0, 0, 0, WhistleblowerFile_v_64, 0, 0, 0, 0, 0, 0, WhistleblowerFile_v_66, 0, models._WhistleblowerFile, 0, 0, 0, 0]),
93-
('WhistleblowerTip', [WhistleblowerTip_v_59, 0, 0, 0, 0, 0, 0, 0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1])
53+
('ArchivedSchema', [models._ArchivedSchema, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]),
54+
('AuditLog', [-1, -1, AuditLog_v_61, 0, 0, 0, 0, 0, 0, 0, models._AuditLog, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]),
55+
('Comment', [Comment_v_64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, Comment_v_71, 0, 0, 0, 0, 0, 0, models._Comment]),
56+
('Config', [models._Config, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]),
57+
('ConfigL10N', [models._ConfigL10N, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]),
58+
('ContentForwarding', [-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, models._ContentForwarding, 0, 0, 0]),
59+
('Context', [Context_v_61, 0, 0, 0, 0, 0, 0, 0, 0, 0, Context_v_63, 0, models._Context, 0, 0, 0, 0, 0, 0, 0, 0]),
60+
('CustomTexts', [models._CustomTexts, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]),
61+
('EnabledLanguage', [models._EnabledLanguage, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]),
62+
('Field', [Field_v_68, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, models._Field, 0, 0, 0]),
63+
('FieldAttr', [FieldAttr_v_52, models._FieldAttr, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]),
64+
('FieldOption', [models._FieldOption, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]),
65+
('FieldOptionTriggerField', [models._FieldOptionTriggerField, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]),
66+
('FieldOptionTriggerStep', [models._FieldOptionTriggerStep, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]),
67+
('File', [File_v_53, 0, models._File, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]),
68+
('IdentityAccessRequest', [IdentityAccessRequest_v_64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, models._IdentityAccessRequest, 0, 0, 0, 0, 0, 0, 0]),
69+
('IdentityAccessRequestCustodian', [-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, models._IdentityAccessRequestCustodian, 0, 0, 0, 0, 0, 0, 0]),
70+
('InternalFile', [InternalFile_v_64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, InternalFile_v_68, 0, 0, 0, InternalFile_v_71, 0, 0, models._InternalFile]),
71+
('InternalTip', [InternalTip_v_52, InternalTip_v_57, 0, 0, 0, 0, InternalTip_v_59, 0, InternalTip_v_63, 0, 0, 0, InternalTip_v_64, InternalTip_v_66, 0, models._InternalTip, 0, 0, 0, 0, 0]),
72+
('InternalTipAnswers', [InternalTipAnswers_v_68, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, InternalTipAnswers_v_69, models._InternalTipAnswers, 0, 0]),
73+
('InternalTipData', [models._InternalTipData, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]),
74+
('InternalTipForwarding', [-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, models._InternalTipForwarding, 0, 0, 0]),
75+
('Mail', [Mail_v_68, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, models._Mail, 0, 0, 0]),
76+
('Message', [Message_v_64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, -1, -1, -1, -1, -1, -1, -1, -1]),
77+
('Questionnaire', [models._Questionnaire, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]),
78+
('ReceiverContext', [models._ReceiverContext, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]),
79+
('ReceiverFile', [ReceiverFile_v_57, 0, 0, 0, 0, 0, ReceiverFile_v_64, 0, 0, 0, 0, 0, 0, ReceiverFile_v_66, 0, ReceiverFile_v_68, 0, ReceiverFile_v_71, 0, 0, models._ReceiverFile]),
80+
('ReceiverTip', [ReceiverTip_v_52, ReceiverTip_v_57, 0, 0, 0, 0, ReceiverTip_v_58, ReceiverTip_v_59, ReceiverTip_v_61, 0, ReceiverTip_v_64, 0, 0, models._ReceiverTip, 0, 0, 0, 0, 0, 0, 0]),
81+
('Redaction', [-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, Redaction_v_66, 0, models._Redaction, 0, 0, 0, 0, 0]),
82+
('Redirect', [models._Redirect, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]),
83+
('SubmissionStatus', [SubmissionStatus_v_64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, models._SubmissionStatus, 0, 0, 0, 0, 0, 0]),
84+
('SubmissionSubStatus', [SubmissionSubStatus_v_64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, SubmissionSubStatus_v_65, 0, models._SubmissionSubStatus, 0, 0, 0, 0, 0]),
85+
('SubmissionStatusChange', [SubmissionStatusChange_v_54, 0, 0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1]),
86+
('Step', [models._Step, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]),
87+
('Subscriber', [Subscriber_v_52, Subscriber_v_62, 0, 0, 0, 0, 0, 0, 0, 0, 0, Subscriber_v_67, 0, 0, 0, 0, Subscriber_v_68, models._Subscriber, 0, 0, 0]),
88+
('Tenant', [Tenant_v_52, Tenant_v_68, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, Tenant_v_70, 0, models._Tenant, 0]),
89+
('User', [User_v_52, User_v_54, 0, User_v_56, 0, User_v_61, 0, 0, 0, 0, User_v_64, 0, 0, User_v_66, 0, User_v_68, 0, User_v_69, 0, models._User, 0]),
90+
('UserProfile', [-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, models._UserProfile, 0]),
91+
('UserProfilePermission', [-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, models._UserProfilePermission, 0]),
92+
('UserProfileRole', [-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, models._UserProfileRole, 0]),
93+
('WhistleblowerFile', [WhistleblowerFile_v_57, 0, 0, 0, 0, 0, WhistleblowerFile_v_64, 0, 0, 0, 0, 0, 0, WhistleblowerFile_v_66, 0, models._WhistleblowerFile, 0, 0, 0, 0, 0]),
94+
('WhistleblowerTip', [WhistleblowerTip_v_59, 0, 0, 0, 0, 0, 0, 0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1])
9495
])
9596

9697

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
from globaleaks.models.enums import EnumStateFile, EnumVisibility
2+
from globaleaks.db.migrations.update import MigrationBase
3+
from globaleaks.models import Model
4+
from globaleaks.models.properties import *
5+
from globaleaks.utils.utility import datetime_now, datetime_null
6+
7+
8+
class Comment_v_71(Model):
9+
__tablename__ = 'comment'
10+
11+
id = Column(UnicodeText(36), primary_key=True, default=uuid4)
12+
creation_date = Column(DateTime, default=datetime_now, nullable=False)
13+
internaltip_id = Column(UnicodeText(36), nullable=False, index=True)
14+
author_id = Column(UnicodeText(36))
15+
content = Column(UnicodeText, nullable=False)
16+
visibility = Column(Enum(EnumVisibility), default='public', nullable=False)
17+
new = Column(Boolean, default=True, nullable=False)
18+
19+
20+
class InternalFile_v_71(Model):
21+
__tablename__ = 'internalfile'
22+
23+
id = Column(UnicodeText(36), primary_key=True, default=uuid4)
24+
creation_date = Column(DateTime, default=datetime_now, nullable=False)
25+
internaltip_id = Column(UnicodeText(36), nullable=False, index=True)
26+
name = Column(UnicodeText, nullable=False)
27+
content_type = Column(JSON, default='', nullable=False)
28+
size = Column(JSON, default='', nullable=False)
29+
new = Column(Boolean, default=True, nullable=False)
30+
reference_id = Column(UnicodeText(36), default='', nullable=False)
31+
verification_date = Column(DateTime, nullable=True)
32+
state = Column(Enum(EnumStateFile), default='pending', nullable=False)
33+
34+
35+
class ReceiverFile_v_71(Model):
36+
__tablename__ = 'receiverfile'
37+
38+
id = Column(UnicodeText(36), primary_key=True, default=uuid4)
39+
internaltip_id = Column(UnicodeText(36), nullable=False, index=True)
40+
author_id = Column(UnicodeText(36))
41+
name = Column(UnicodeText, nullable=False)
42+
size = Column(Integer, nullable=False)
43+
content_type = Column(UnicodeText, nullable=False)
44+
creation_date = Column(DateTime, default=datetime_now, nullable=False)
45+
access_date = Column(DateTime, default=datetime_null, nullable=False)
46+
description = Column(UnicodeText, default="", nullable=False)
47+
visibility = Column(Enum(EnumVisibility), default='public', nullable=False)
48+
new = Column(Boolean, default=True, nullable=False)
49+
50+
51+
class MigrationScript(MigrationBase):
52+
def migrate_Comment(self):
53+
old_comments = self.session_old.query(self.model_from['Comment']).all()
54+
new_comments = []
55+
56+
for old_obj in old_comments:
57+
new_comment = self.model_to['Comment']()
58+
59+
for key in new_comment.__mapper__.column_attrs.keys():
60+
if hasattr(old_obj, key):
61+
setattr(new_comment, key, getattr(old_obj, key))
62+
63+
new_comment.hash_sha256 = ''
64+
new_comment.hash_sha512 = ''
65+
66+
new_comments.append(new_comment)
67+
68+
self.session_new.add_all(new_comments)
69+
70+
def migrate_InternalFile(self):
71+
old_rows = self.session_old.query(self.model_from['InternalFile']).all()
72+
73+
for old in old_rows:
74+
new = self.model_to['InternalFile']()
75+
76+
for col in new.__mapper__.column_attrs.keys():
77+
if hasattr(old, col):
78+
setattr(new, col, getattr(old, col))
79+
80+
new.hash_sha256 = ''
81+
new.hash_sha512 = ''
82+
83+
self.session_new.add(new)
84+
85+
def migrate_ReceiverFile(self):
86+
old_rows = self.session_old.query(self.model_from['ReceiverFile']).all()
87+
88+
for old in old_rows:
89+
new = self.model_to['ReceiverFile']()
90+
91+
for col in new.__mapper__.column_attrs.keys():
92+
if hasattr(old, col):
93+
setattr(new, col, getattr(old, col))
94+
95+
new.hash_sha256 = ''
96+
new.hash_sha512 = ''
97+
98+
self.session_new.add(new)

backend/globaleaks/handlers/base.py

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
import mimetypes
33
import os
44
import re
5+
import binascii
56

67
from datetime import datetime
78

@@ -24,8 +25,11 @@
2425
from globaleaks.utils.pgp import PGPContext
2526
from globaleaks.utils.securetempfile import SecureTemporaryFile
2627
from globaleaks.utils.utility import datetime_now
28+
from cryptography.hazmat.primitives import hashes
29+
from cryptography.hazmat.backends import default_backend
2730

2831
mimetypes.add_type('text/javascript', '.js')
32+
crypto_backend = default_backend()
2933

3034

3135
def decodeString(string):
@@ -348,7 +352,24 @@ def write_file_as_download(self, filename, fp, pgp_key=''):
348352
'attachment; filename="%s"' % filename)
349353

350354
return serve_file(self.request, fp)
351-
355+
356+
def compute_file_hashes(self, filepath, chunk_size=8192):
357+
sha256_ctx = hashes.Hash(hashes.SHA256(), backend=crypto_backend)
358+
sha512_ctx = hashes.Hash(hashes.SHA512(), backend=crypto_backend)
359+
360+
with open(filepath, 'rb') as fh:
361+
while True:
362+
chunk = fh.read(chunk_size)
363+
if not chunk:
364+
break
365+
sha256_ctx.update(chunk)
366+
sha512_ctx.update(chunk)
367+
368+
sha256_digest = binascii.b2a_hex(sha256_ctx.finalize()).decode()
369+
sha512_digest = binascii.b2a_hex(sha512_ctx.finalize()).decode()
370+
371+
return sha256_digest, sha512_digest
372+
352373
def process_file_upload(self):
353374
if b'flowFilename' not in self.request.args:
354375
return
@@ -388,6 +409,7 @@ def process_file_upload(self):
388409
filename = os.path.basename(self.request.args[b'flowFilename'][0].decode())
389410
mime_type, _ = mimetypes.guess_type(filename)
390411
mime_type = mime_type or 'application/octet-stream' # Default MIME type if None
412+
sha256_digest, sha512_digest = self.compute_file_hashes(f.filepath)
391413

392414
# Prepare the uploaded file metadata
393415
self.uploaded_file = {
@@ -400,7 +422,9 @@ def process_file_upload(self):
400422
'body': f,
401423
'description': self.request.args.get(b'description', [''])[0],
402424
'reference_id': self.request.args.get(b'reference_id', [''])[0],
403-
'visibility': self.request.args.get(b'visibility', [''])[0]
425+
'visibility': self.request.args.get(b'visibility', [''])[0],
426+
'hash_sha256': sha256_digest,
427+
'hash_sha512': sha512_digest
404428
}
405429

406430
def write_upload_plaintext_to_disk(self, destination):

backend/globaleaks/handlers/recipient/rtip.py

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@
2626
from globaleaks.orm import db_get, db_del, db_log, transact
2727
from globaleaks.rest import errors, requests
2828
from globaleaks.state import State
29-
from globaleaks.utils.crypto import GCE
29+
from globaleaks.utils.crypto import GCE, sha256, sha512
3030
from globaleaks.utils.fs import directory_traversal_check
3131
from globaleaks.utils.log import log
3232
from globaleaks.utils.templating import Templating
@@ -647,7 +647,7 @@ def register_rfile_on_db(session, tid, user_id, itip_id, uploaded_file):
647647
itip.update_date = rtip.last_access
648648

649649
if itip.crypto_tip_pub_key:
650-
for k in ['name', 'description', 'type', 'size']:
650+
for k in ['name', 'description', 'type', 'size', 'hash_sha256', 'hash_sha512']:
651651
if k == 'size':
652652
uploaded_file[k] = str(uploaded_file[k])
653653
uploaded_file[k] = Base64Encoder.encode(GCE.asymmetric_encrypt(itip.crypto_tip_pub_key, uploaded_file[k]))
@@ -661,6 +661,8 @@ def register_rfile_on_db(session, tid, user_id, itip_id, uploaded_file):
661661
new_file.size = uploaded_file['size']
662662
new_file.internaltip_id = itip.id
663663
new_file.visibility = uploaded_file['visibility']
664+
new_file.hash_sha256 = uploaded_file['hash_sha256']
665+
new_file.hash_sha512 = uploaded_file['hash_sha512']
664666

665667
session.add(new_file)
666668

@@ -1042,22 +1044,30 @@ def create_comment(session, tid, user_id, itip_id, content, visibility='public')
10421044
rtip.last_access = datetime_now()
10431045
if visibility == 'public':
10441046
itip.update_date = rtip.last_access
1045-
1047+
1048+
hash_sha256 = sha256(content)
1049+
hash_sha512 = sha512(content)
10461050
_content = content
10471051
if itip.crypto_tip_pub_key:
10481052
_content = Base64Encoder.encode(GCE.asymmetric_encrypt(itip.crypto_tip_pub_key, content)).decode()
1053+
_hash_sha256 = Base64Encoder.encode(GCE.asymmetric_encrypt(itip.crypto_tip_pub_key, hash_sha256)).decode()
1054+
_hash_sha512 = Base64Encoder.encode(GCE.asymmetric_encrypt(itip.crypto_tip_pub_key, hash_sha512)).decode()
10491055

10501056
comment = models.Comment()
10511057
comment.internaltip_id = itip.id
10521058
comment.type = 'receiver'
10531059
comment.author_id = rtip.receiver_id
10541060
comment.content = _content
10551061
comment.visibility = visibility
1062+
comment.hash_sha256 = _hash_sha256
1063+
comment.hash_sha512 = _hash_sha512
10561064
session.add(comment)
10571065
session.flush()
10581066

10591067
ret = serializers.serialize_comment(session, comment)
10601068
ret['content'] = content
1069+
ret['hash_sha256'] = hash_sha256
1070+
ret['hash_sha512'] = hash_sha512
10611071
return ret
10621072

10631073

0 commit comments

Comments
 (0)