@@ -442,11 +442,11 @@ def __init__(self, instance, request, env, form=None, translator=None):
442
442
# will never arrive.
443
443
# If not defined, set CONTENT_LENGTH to 0 so it doesn't
444
444
# hang reading the data.
445
- if self .env ['REQUEST_METHOD' ] in ['OPTIONS' , 'DELETE' , 'PATCH' ]:
446
- if 'CONTENT_LENGTH' not in self .env :
447
- self .env ['CONTENT_LENGTH' ] = 0
448
- logger .debug ("Setting CONTENT_LENGTH to 0 for method: %s" ,
449
- self .env ['REQUEST_METHOD' ])
445
+ if self .env ['REQUEST_METHOD' ] in ['OPTIONS' , 'DELETE' , 'PATCH' ] \
446
+ and 'CONTENT_LENGTH' not in self .env :
447
+ self .env ['CONTENT_LENGTH' ] = 0
448
+ logger .debug ("Setting CONTENT_LENGTH to 0 for method: %s" ,
449
+ self .env ['REQUEST_METHOD' ])
450
450
451
451
# cgi.FieldStorage must save all data as
452
452
# binary/bytes. Subclass BinaryFieldStorage does this.
@@ -496,8 +496,7 @@ def __init__(self, instance, request, env, form=None, translator=None):
496
496
497
497
def _gen_nonce (self ):
498
498
""" generate a unique nonce """
499
- n = b2s (base64 .b32encode (random_ .token_bytes (40 )))
500
- return n
499
+ return b2s (base64 .b32encode (random_ .token_bytes (40 )))
501
500
502
501
def setTranslator (self , translator = None ):
503
502
"""Replace the translation engine
@@ -694,7 +693,8 @@ def handle_rest(self):
694
693
if (self .is_cors_preflight ()):
695
694
self .handle_preflight ()
696
695
return
697
- elif not self .db .security .hasPermission ('Rest Access' , self .userid ):
696
+
697
+ if not self .db .security .hasPermission ('Rest Access' , self .userid ):
698
698
output = s2b ('{ "error": { "status": 403, "msg": "Forbidden." } }' )
699
699
self .reject_request (output ,
700
700
message_type = "application/json" ,
@@ -811,14 +811,11 @@ def inner_main(self):
811
811
self .form_wins = True
812
812
self ._error_message = msg .args
813
813
814
- if csrf_ok :
815
- # csrf checks pass. Run actions etc.
816
- # possibly handle a form submit action (may change
817
- # self.classname and self.template, and may also
818
- # append error/ok_messages)
819
- html = self .handle_action ()
820
- else :
821
- html = None
814
+ # If csrf checks pass. Run actions etc.
815
+ # handle_action() may handle a form submit action.
816
+ # It can change self.classname and self.template,
817
+ # and may also append error/ok_messages.
818
+ html = self .handle_action () if csrf_ok else None
822
819
823
820
if html :
824
821
self .write_html (html )
@@ -883,7 +880,7 @@ def inner_main(self):
883
880
self .response_code = http_ .client .UNAUTHORIZED
884
881
realm = self .instance .config .TRACKER_NAME
885
882
self .setHeader ("WWW-Authenticate" ,
886
- " Basic realm=\ " %s\" " % realm )
883
+ ' Basic realm="%s"' % realm )
887
884
else :
888
885
self .response_code = http_ .client .FORBIDDEN
889
886
self .renderFrontPage (str (message ))
@@ -1041,10 +1038,7 @@ def determine_charset(self):
1041
1038
1042
1039
def _decode_charref (matchobj ):
1043
1040
num = matchobj .group (1 )
1044
- if num [0 ].lower () == 'x' :
1045
- uc = int (num [1 :], 16 )
1046
- else :
1047
- uc = int (num )
1041
+ uc = int (num [1 :], 16 ) if num [0 ].lower () == 'x' else int (num )
1048
1042
return uchr (uc )
1049
1043
1050
1044
for field_name in self .form :
@@ -1235,7 +1229,7 @@ def determine_user(self, is_api=False):
1235
1229
1236
1230
# will be used later to override the get_roles method
1237
1231
# having it defined as truthy allows it to be used.
1238
- override_get_roles = lambda self : iter_roles ( # noqa: E731
1232
+ override_get_roles = lambda self : iter_roles ( # noqa: ARG005
1239
1233
',' .join (token ['roles' ]))
1240
1234
1241
1235
# if user was not set by http authorization, try session lookup
@@ -1291,6 +1285,8 @@ def check_anonymous_access(self):
1291
1285
raise SeriousError (
1292
1286
self ._ ('broken form: multiple @action values submitted' ))
1293
1287
elif action != '' :
1288
+ # '' is value when no action parameter was found so run
1289
+ # this to extract action string value when action found.
1294
1290
action = action .value .lower ()
1295
1291
if action in ('login' , 'register' ):
1296
1292
return
@@ -1302,8 +1298,8 @@ def check_anonymous_access(self):
1302
1298
return
1303
1299
1304
1300
# otherwise for everything else
1305
- if self .user == 'anonymous' :
1306
- if not self .db .security .hasPermission ('Web Access' , self .userid ):
1301
+ if self .user == 'anonymous' and \
1302
+ not self .db .security .hasPermission ('Web Access' , self .userid ):
1307
1303
raise Unauthorised (self ._ ("Anonymous users are not "
1308
1304
"allowed to use the web interface" ))
1309
1305
@@ -1326,10 +1322,7 @@ def is_origin_header_ok(self, api=False, credentials=False):
1326
1322
try :
1327
1323
origin = self .env ['HTTP_ORIGIN' ]
1328
1324
except KeyError :
1329
- if self .env ['REQUEST_METHOD' ] == 'GET' :
1330
- return True
1331
- else :
1332
- return False
1325
+ return self .env ['REQUEST_METHOD' ] == 'GET'
1333
1326
1334
1327
# note base https://host/... ends host with with a /,
1335
1328
# so add it to origin.
@@ -1478,7 +1471,7 @@ def handle_csrf(self, api=False):
1478
1471
"ORIGIN" ,
1479
1472
"REFERER" ,
1480
1473
"X-FORWARDED-HOST" ,
1481
- "HOST"
1474
+ "HOST" ,
1482
1475
]
1483
1476
1484
1477
header_pass = 0 # count of passing header checks
@@ -1581,21 +1574,20 @@ def handle_csrf(self, api=False):
1581
1574
raise UsageError (self ._ ("Unable to verify sufficient headers" ))
1582
1575
1583
1576
enforce = config ['WEB_CSRF_ENFORCE_HEADER_X-REQUESTED-WITH' ]
1584
- if api :
1585
- if enforce in ['required' , 'yes' ]:
1586
- # if we get here we have usually passed at least one
1587
- # header check. We check for presence of this custom
1588
- # header for xmlrpc/rest calls only.
1589
- # E.G. X-Requested-With: XMLHttpRequest
1590
- # Note we do not use CSRF nonces for xmlrpc/rest requests.
1591
- #
1592
- # see: https://www.owasp.org/index.php/Cross-Site_Request_Forgery_(CSRF)_Prevention_Cheat_Sheet#Protecting_REST_Services:_Use_of_Custom_Request_Headers
1593
- if 'HTTP_X_REQUESTED_WITH' not in self .env :
1594
- logger .error (self ._ (
1595
- '' "csrf X-REQUESTED-WITH xmlrpc required header "
1596
- '' "check failed for user%s." ),
1597
- current_user )
1598
- raise UsageError (self ._ ("Required Header Missing" ))
1577
+ if api and enforce in ['required' , 'yes' ]:
1578
+ # if we get here we have usually passed at least one
1579
+ # header check. We check for presence of this custom
1580
+ # header for xmlrpc/rest calls only.
1581
+ # E.G. X-Requested-With: XMLHttpRequest
1582
+ # Note we do not use CSRF nonces for xmlrpc/rest requests.
1583
+ #
1584
+ # see: https://www.owasp.org/index.php/Cross-Site_Request_Forgery_(CSRF)_Prevention_Cheat_Sheet#Protecting_REST_Services:_Use_of_Custom_Request_Headers
1585
+ if 'HTTP_X_REQUESTED_WITH' not in self .env :
1586
+ logger .error (self ._ (
1587
+ '' "csrf X-REQUESTED-WITH xmlrpc required header "
1588
+ '' "check failed for user%s." ),
1589
+ current_user )
1590
+ raise UsageError (self ._ ("Required Header Missing" ))
1599
1591
1600
1592
# Expire old csrf tokens now so we don't use them. These will
1601
1593
# be committed after the otks.destroy below. Note that the
@@ -1703,17 +1695,16 @@ def opendb(self, username):
1703
1695
if not hasattr (self , 'db' ):
1704
1696
self .db = self .instance .open (username )
1705
1697
self .db .tx_Source = "web"
1706
- else :
1707
- if self .instance .optimize :
1698
+ elif self .instance .optimize :
1708
1699
self .db .setCurrentUser (username )
1709
1700
self .db .tx_Source = "web"
1710
- else :
1711
- self .db .close ()
1712
- self .db = self .instance .open (username )
1713
- self .db .tx_Source = "web"
1714
- # The old session API refers to the closed database;
1715
- # we can no longer use it.
1716
- self .session_api = Session (self )
1701
+ else :
1702
+ self .db .close ()
1703
+ self .db = self .instance .open (username )
1704
+ self .db .tx_Source = "web"
1705
+ # The old session API refers to the closed database;
1706
+ # we can no longer use it.
1707
+ self .session_api = Session (self )
1717
1708
1718
1709
# match designator in URL stripping leading 0's. So:
1719
1710
# https://issues.roundup-tracker.org/issue002551190 is the same as
@@ -1793,7 +1784,7 @@ def determine_context(self, dre=dre_url):
1793
1784
else :
1794
1785
self .template = ''
1795
1786
return
1796
- elif path [0 ] in ('_file' , '@@file' ):
1787
+ if path [0 ] in ('_file' , '@@file' ):
1797
1788
raise SendStaticFile (os .path .join (* path [1 :]))
1798
1789
else :
1799
1790
self .classname = path [0 ]
@@ -1973,10 +1964,7 @@ def serve_static_file(self, file):
1973
1964
file = str (file )
1974
1965
mime_type = mimetypes .guess_type (file )[0 ]
1975
1966
if not mime_type :
1976
- if file .endswith ('.css' ):
1977
- mime_type = 'text/css'
1978
- else :
1979
- mime_type = 'text/plain'
1967
+ mime_type = 'text/css' if file .endswith ('.css' ) else 'text/plain'
1980
1968
1981
1969
# get filename: given a/b/c.js extract c.js
1982
1970
fn = file .rpartition ("/" )[2 ]
@@ -2079,12 +2067,9 @@ def selectTemplate(self, name, view):
2079
2067
if (view and view .find ('|' ) != - 1 ):
2080
2068
# we have alternate templates, parse them apart.
2081
2069
(oktmpl , errortmpl ) = view .split ("|" , 2 )
2082
- if self ._error_message :
2083
- # we have an error, use errortmpl
2084
- view = errortmpl
2085
- else :
2086
- # no error message recorded, use oktmpl
2087
- view = oktmpl
2070
+
2071
+ # Choose the right template
2072
+ view = errortmpl if self ._error_message else oktmpl
2088
2073
2089
2074
loader = self .instance .templates
2090
2075
@@ -2135,7 +2120,7 @@ def renderContext(self):
2135
2120
# catch errors so we can handle PT rendering errors more nicely
2136
2121
args = {
2137
2122
'ok_message' : self ._ok_message ,
2138
- 'error_message' : self ._error_message
2123
+ 'error_message' : self ._error_message ,
2139
2124
}
2140
2125
pt = self .instance .templates .load (tplname )
2141
2126
# let the template render figure stuff out
@@ -2189,8 +2174,7 @@ def renderContext(self):
2189
2174
# than the one we tried to generate above.
2190
2175
if sys .version_info [0 ] > 2 :
2191
2176
raise exc_info [0 ](exc_info [1 ]).with_traceback (exc_info [2 ])
2192
- else :
2193
- exec ('raise exc_info[0], exc_info[1], exc_info[2]' ) # nosec
2177
+ exec ('raise exc_info[0], exc_info[1], exc_info[2]' ) # nosec
2194
2178
2195
2179
def renderError (self , error , response_code = 400 , use_template = True ):
2196
2180
self .response_code = response_code
@@ -2222,7 +2206,7 @@ def renderError(self, error, response_code=400, use_template=True):
2222
2206
2223
2207
args = {
2224
2208
'ok_message' : self ._ok_message ,
2225
- 'error_message' : self ._error_message
2209
+ 'error_message' : self ._error_message ,
2226
2210
}
2227
2211
2228
2212
try :
@@ -2573,7 +2557,7 @@ def handle_range_header(self, length, etag):
2573
2557
# If the condition doesn't match the entity tag, then we
2574
2558
# must send the client the entire file.
2575
2559
if if_range != etag :
2576
- return
2560
+ return None
2577
2561
# The grammar for the Range header value is:
2578
2562
#
2579
2563
# ranges-specifier = byte-ranges-specifier
@@ -2761,13 +2745,10 @@ def write_file(self, filename):
2761
2745
self ._socket_op (self .request .sendfile , filename , offset , length )
2762
2746
return
2763
2747
# Fallback to the "write" operation.
2764
- f = open (filename , 'rb' )
2765
- try :
2748
+ with open (filename , 'rb' ) as f :
2766
2749
if offset :
2767
2750
f .seek (offset )
2768
2751
content = f .read (length )
2769
- finally :
2770
- f .close ()
2771
2752
self .write (content )
2772
2753
2773
2754
def setHeader (self , header , value ):
0 commit comments