Skip to content
GitLab
Projects
Groups
Snippets
Help
Loading...
Help
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
M
minor
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Service Desk
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Packages & Registries
Packages & Registries
Container Registry
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Christian Knuchel
minor
Commits
fdc46e81
Commit
fdc46e81
authored
Sep 17, 2019
by
Fence
🌈
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
add Adminlogins & auth backend
parent
1456aa7d
Changes
9
Hide whitespace changes
Inline
Side-by-side
Showing
9 changed files
with
162 additions
and
4 deletions
+162
-4
minor/app.py
minor/app.py
+3
-0
minor/cli/__init__.py
minor/cli/__init__.py
+2
-0
minor/cli/admin.py
minor/cli/admin.py
+54
-0
minor/controller/__init__.py
minor/controller/__init__.py
+1
-0
minor/controller/auth.py
minor/controller/auth.py
+38
-0
minor/crypto.py
minor/crypto.py
+39
-1
minor/decorators.py
minor/decorators.py
+3
-2
minor/model.py
minor/model.py
+21
-1
requirements.txt
requirements.txt
+1
-0
No files found.
minor/app.py
View file @
fdc46e81
from
flask
import
Flask
from
minor.controller
import
ApiController
,
MusicController
,
CoverController
from
minor.controller
import
AuthController
from
minor.error_handlers
import
set_error_handlers
...
...
@@ -7,6 +8,7 @@ class App(object):
def
__init__
(
self
,
config
):
self
.
_flask
=
Flask
(
__name__
)
self
.
_flask
.
config
[
'MONGODB_SETTINGS'
]
=
{
'db'
:
'minor'
}
self
.
_flask
.
config
[
'JWT_SEKRIT'
]
=
"sekrit"
self
.
_flask
.
config
.
update
(
config
)
set_error_handlers
(
self
.
_flask
)
...
...
@@ -14,6 +16,7 @@ class App(object):
db
.
init_app
(
self
.
_flask
)
ApiController
(
self
).
register
(
self
.
_flask
)
AuthController
(
self
).
register
(
self
.
_flask
)
MusicController
(
self
.
_flask
.
config
[
"MUSIC_UPLOAD_DIR"
],
self
.
_flask
.
config
[
"IMAGE_UPLOAD_DIR"
]
...
...
minor/cli/__init__.py
View file @
fdc46e81
import
click
from
.rsa
import
rsa
from
.admin
import
admin
@
click
.
group
()
...
...
@@ -9,3 +10,4 @@ def cli(ctx):
cli
.
add_command
(
rsa
)
cli
.
add_command
(
admin
)
minor/cli/admin.py
0 → 100644
View file @
fdc46e81
import
sys
import
getpass
import
click
from
mongoengine
import
connect
from
minor.model
import
AdminLogin
@
click
.
group
()
@
click
.
pass_context
def
admin
(
ctx
):
ctx
.
db
=
ctx
.
parent
.
db
connect
(
ctx
.
db
)
@
admin
.
command
(
"list"
)
def
list_logins
():
for
login
in
AdminLogin
.
objects
:
click
.
echo
(
login
.
email
)
@
admin
.
command
(
"add"
)
@
click
.
argument
(
"email"
,
nargs
=
1
)
def
add_login
(
email
):
# only add if the issuer does not exist already
try
:
AdminLogin
.
objects
.
get
(
email
=
email
)
click
.
echo
(
"A login for the email
\"
{}
\"
does already exist"
.
format
(
email
)
)
return
sys
.
exit
(
1
)
except
AdminLogin
.
DoesNotExist
:
login
=
AdminLogin
(
email
=
email
)
password
=
getpass
.
getpass
(
"enter password: "
)
password2
=
getpass
.
getpass
(
"re-enter password: "
)
if
password
!=
password2
:
click
.
echo
(
"passwords do not match"
)
return
sys
.
exit
(
1
)
login
.
set_new_password
(
password
)
login
.
save
()
click
.
echo
(
"login for email
\"
{}
\"
added"
.
format
(
email
))
@
admin
.
command
(
"rm"
)
@
click
.
argument
(
"email"
,
nargs
=
1
)
def
rm_login
(
email
):
try
:
key
=
AdminLogin
.
objects
.
get
(
email
=
email
)
key
.
delete
()
click
.
echo
(
"login for
\"
{}
\"
deleted"
.
format
(
email
))
except
AdminLogin
.
DoesNotExist
:
click
.
echo
(
"login for
\"
{}
\"
does not exist"
.
format
(
email
))
return
sys
.
exit
(
1
)
minor/controller/__init__.py
View file @
fdc46e81
from
minor.controller.api
import
ApiController
from
minor.controller.music
import
MusicController
from
minor.controller.covers
import
CoverController
from
minor.controller.auth
import
AuthController
minor/controller/auth.py
0 → 100644
View file @
fdc46e81
from
flask
import
request
,
jsonify
from
flask_controller
import
FlaskController
,
route
from
minor.model
import
AdminLogin
import
minor.crypto
@
route
(
"/auth"
)
class
AuthController
(
FlaskController
):
def
__init__
(
self
,
app
):
self
.
_app
=
app
self
.
_secret
=
app
.
_flask
.
config
[
"JWT_SEKRIT"
]
@
route
(
"/login"
,
methods
=
[
"POST"
])
def
index
(
self
):
json
=
request
.
get_json
()
if
json
is
not
None
:
email
=
json
.
get
(
"email"
)
password
=
json
.
get
(
"password"
)
if
email
is
not
None
and
password
is
not
None
:
try
:
login
=
AdminLogin
.
objects
.
get
(
email
=
email
)
if
login
.
verify_password
(
password
):
token
=
minor
.
crypto
.
issue_token
(
email
,
self
.
_secret
)
return
jsonify
({
"code"
:
200
,
"message"
:
"success"
,
"value"
:
token
}),
200
except
AdminLogin
.
DoesNotExist
:
return
jsonify
({
"code"
:
403
,
"message"
:
"wrong creds"
}),
403
return
jsonify
({
"code"
:
403
,
"message"
:
"wrong creds"
}),
403
minor/crypto.py
View file @
fdc46e81
import
jwt
from
datetime
import
datetime
,
timedelta
from
minor.model
import
TrustedRsaKey
def
get_asymetric_jwt_payload
(
self
,
token
):
def
get_payload_from_jwt
(
token
,
secret
):
"""
Returns the payload from a jwt if it can be verified, None otherwise
"""
header
=
jwt
.
get_unverified_header
(
token
)
if
header
[
"alg"
].
startswith
(
"HS"
):
return
get_symetric_jwt_payload
(
token
)
elif
header
[
"alg"
].
startswith
(
"RS"
):
return
get_asymetric_jwt_payload
(
token
,
secret
)
else
:
return
None
def
get_symetric_jwt_payload
(
token
,
secret
):
try
:
checked_payload
=
jwt
.
decode
(
token
,
secret
)
# every token issued by this webservice have all privileges
checked_payload
[
"write_permission"
]
=
True
return
checked_payload
except
Exception
:
return
None
def
get_asymetric_jwt_payload
(
token
):
payload
=
jwt
.
decode
(
token
,
""
,
verify
=
False
)
try
:
...
...
@@ -14,7 +39,20 @@ def get_asymetric_jwt_payload(self, token):
try
:
key
=
issuer
.
key
checked_payload
=
jwt
.
decode
(
token
,
key
)
checked_payload
[
"write_permission"
]
=
issuer
.
can_write
return
checked_payload
except
Exception
:
return
None
return
None
def
issue_token
(
email
,
secret
):
payload
=
{}
# TODO add issuer to the config
payload
[
"iss"
]
=
"minor"
payload
[
"aud"
]
=
email
payload
[
"iat"
]
=
datetime
.
utcnow
()
payload
[
"exp"
]
=
datetime
.
utcnow
()
+
timedelta
(
minutes
=
30
)
# TODO maybe add jti?
token
=
jwt
.
encode
(
payload
,
secret
,
algorithm
=
'HS256'
)
return
str
(
token
)
minor/decorators.py
View file @
fdc46e81
...
...
@@ -6,12 +6,13 @@ from minor import crypto
def
auth_required
(
f
):
@
wraps
(
f
)
def
decorated_function
(
self
,
*
args
,
**
kwargs
):
auth
=
request
.
headers
[
"Authorization"
]
auth
=
request
.
headers
.
get
(
"Authorization"
)
if
auth
is
not
None
:
auth
=
auth
.
split
(
" "
)
if
auth
[
0
]
==
"Bearer"
:
# print(auth[1])
payload
=
crypto
.
get_asymetric_jwt_payload
(
auth
[
1
])
secret
=
self
.
app
.
config
[
"JWT_SEKRIT"
]
payload
=
crypto
.
get_payload_from_jwt
(
auth
[
1
],
secret
)
if
payload
is
not
None
:
kwargs
[
"payload"
]
=
payload
return
f
(
self
,
*
args
,
**
kwargs
)
...
...
minor/model.py
View file @
fdc46e81
import
bcrypt
from
mongoengine
import
Document
,
StringField
,
IntField
from
mongoengine
import
ReferenceField
,
ListField
,
CASCADE
from
mongoengine
import
ReferenceField
,
ListField
,
CASCADE
,
BooleanField
from
flask_mongoengine
import
MongoEngine
db
=
MongoEngine
()
...
...
@@ -24,3 +25,22 @@ class Cover(Document):
class
TrustedRsaKey
(
Document
):
issuer
=
StringField
(
required
=
True
)
key
=
StringField
(
required
=
True
)
can_write
=
BooleanField
(
default
=
False
)
class
AdminLogin
(
Document
):
email
=
StringField
(
required
=
True
)
password
=
StringField
(
required
=
True
)
def
set_new_password
(
self
,
new_password
):
hash_bytes
=
bcrypt
.
hashpw
(
new_password
.
encode
(
"utf-8"
),
bcrypt
.
gensalt
()
)
self
.
password
=
hash_bytes
.
decode
(
"utf-8"
)
def
verify_password
(
self
,
input_pw
):
return
bcrypt
.
checkpw
(
input_pw
.
encode
(
"utf-8"
),
self
.
password
.
encode
(
"utf-8"
)
)
requirements.txt
View file @
fdc46e81
...
...
@@ -5,3 +5,4 @@ git+https://github.com/AlexFence/FlaskController.git
mutagen
click
tabulate
bcrypt
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment