10
10
from flask import (Blueprint , render_template , flash , redirect , url_for , g ,
11
11
session , current_app , request , Markup , abort )
12
12
from flask_babel import gettext
13
- from sqlalchemy .exc import IntegrityError
14
13
15
14
import store
16
15
17
16
from db import db
18
- from models import Source , Submission , Reply , get_one_or_else
17
+ from models import Submission , Reply , get_one_or_else
18
+ from passphrases import PassphraseGenerator
19
19
from sdconfig import SDConfig
20
20
from source_app .decorators import login_required
21
- from source_app .utils import (logged_in , generate_unique_codename ,
22
- normalize_timestamps , valid_codename )
21
+ from source_app .utils import (logged_in , normalize_timestamps ,
22
+ valid_codename )
23
23
from source_app .forms import LoginForm , SubmissionForm
24
+ from source_user import create_source_user , SourcePassphraseCollisionError , \
25
+ SourceDesignationCollisionError
26
+
27
+ from securedrop .models import Source
28
+ from securedrop .source_user import SourceUser
24
29
25
30
26
31
def make_blueprint (config : SDConfig ) -> Blueprint :
@@ -40,7 +45,9 @@ def generate() -> Union[str, werkzeug.Response]:
40
45
"notification" )
41
46
return redirect (url_for ('.lookup' ))
42
47
43
- codename = generate_unique_codename (config )
48
+ codename = PassphraseGenerator .get_default ().generate_passphrase (
49
+ preferred_language = g .localeinfo .language
50
+ )
44
51
45
52
# Generate a unique id for each browser tab and associate the codename with this id.
46
53
# This will allow retrieval of the codename displayed in the tab from which the source has
@@ -55,53 +62,45 @@ def generate() -> Union[str, werkzeug.Response]:
55
62
56
63
@view .route ('/create' , methods = ['POST' ])
57
64
def create () -> werkzeug .Response :
58
- if session . get ( ' logged_in' , False ):
65
+ if logged_in ( ):
59
66
flash (gettext ("You are already logged in. Please verify your codename above as it " +
60
67
"may differ from the one displayed on the previous page." ),
61
68
'notification' )
62
69
else :
63
70
tab_id = request .form ['tab_id' ]
64
71
codename = session ['codenames' ][tab_id ]
65
- session ['codename' ] = codename
66
-
67
72
del session ['codenames' ]
68
73
69
- filesystem_id = current_app .crypto_util .hash_codename (codename )
70
74
try :
71
- source = Source (filesystem_id , current_app .crypto_util .display_id ())
72
- except ValueError as e :
73
- current_app .logger .error (e )
74
- flash (
75
- gettext ("There was a temporary problem creating your account. "
76
- "Please try again."
77
- ),
78
- 'error'
75
+ current_app .logger .info ("Creating new source user..." )
76
+ create_source_user (
77
+ db_session = db .session ,
78
+ source_passphrase = codename ,
79
+ source_app_crypto_util = current_app .crypto_util ,
80
+ source_app_storage = current_app .storage ,
79
81
)
80
- return redirect (url_for ('.index' ))
81
-
82
- db .session .add (source )
83
- try :
84
- db .session .commit ()
85
- except IntegrityError as e :
86
- db .session .rollback ()
87
- current_app .logger .error (
88
- "Attempt to create a source with duplicate codename: %s" %
89
- (e ,))
90
-
91
- # Issue 2386: don't log in on duplicates
92
- del session ['codename' ]
82
+ except (SourcePassphraseCollisionError , SourceDesignationCollisionError ) as e :
83
+ current_app .logger .error ("Could not create a source: {}" .format (e ))
93
84
94
85
# Issue 4361: Delete 'logged_in' if it's in the session
95
86
try :
96
87
del session ['logged_in' ]
97
88
except KeyError :
98
89
pass
99
90
100
- abort (500 )
101
- else :
102
- os .mkdir (current_app .storage .path (filesystem_id ))
91
+ flash (
92
+ gettext (
93
+ "There was a temporary problem creating your account. Please try again."
94
+ ),
95
+ "error"
96
+ )
97
+ return redirect (url_for ('.index' ))
103
98
99
+ # All done - source user was successfully created
100
+ current_app .logger .info ("New source user created" )
104
101
session ['logged_in' ] = True
102
+ session ['codename' ] = codename
103
+
105
104
return redirect (url_for ('.lookup' ))
106
105
107
106
@view .route ('/lookup' , methods = ('GET' ,))
@@ -137,7 +136,17 @@ def lookup() -> str:
137
136
138
137
# Generate a keypair to encrypt replies from the journalist
139
138
if not current_app .crypto_util .get_fingerprint (g .filesystem_id ):
140
- current_app .crypto_util .genkeypair (g .filesystem_id , g .codename )
139
+ # TODO(AD): Will be simplified in my next PR by using logged_in_user instead of
140
+ # fetching it from the DB here
141
+ source = session .query (Source ).filter (Source .filesystem_id == g .filesystem_id ).one ()
142
+ source_user = SourceUser (
143
+ db_record = source ,
144
+ filesystem_id = g .filesystem_id ,
145
+ gpg_secret = current_app .crypto_util .hash_codename (
146
+ g .codename , salt = current_app .crypto_util .scrypt_gpg_pepper
147
+ )
148
+ )
149
+ current_app .crypto_util .genkeypair (source_user )
141
150
142
151
return render_template (
143
152
'lookup.html' ,
0 commit comments