Skip to content
This repository has been archived by the owner on Nov 7, 2019. It is now read-only.

Commit

Permalink
Merge pull request #3 from josecoelho96/dev/roles
Browse files Browse the repository at this point in the history
Add roles/permissions system
  • Loading branch information
josecoelho96 authored Sep 22, 2018
2 parents 03f56f0 + 1e8613e commit 14c9732
Show file tree
Hide file tree
Showing 6 changed files with 150 additions and 4 deletions.
7 changes: 5 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ Used to list details of a participant. The `@user` or `user-id` must be provided

## Current features:
- Request origin verification/validation
- Roles/Permissions

## To be added
```./bug <money-change> <description>``` \
Expand All @@ -44,7 +45,6 @@ Can only be performed by admins. Used to make `@user` an admin.
- Auto add users to channels
- Report logs to channel
- Report money receival on buy operation
- Permissions system
- Error codes
- Single user transactions listing

Expand All @@ -54,4 +54,7 @@ Can only be performed by admins. Used to make `@user` an admin.
- IDs are not being verified as unique.

## Bug list
- ...
- ...

## Small fixes
Fix typo in SLACK_REQUEST_TIMESTAMP_MAX_GAP_MINUTES -> SECONDS
9 changes: 8 additions & 1 deletion db/init/create.sql
Original file line number Diff line number Diff line change
Expand Up @@ -49,4 +49,11 @@ CREATE TABLE IF NOT EXISTS transactions (
destination_user_id UUID,
amount NUMERIC(10, 4),
description TEXT
);
);

CREATE TABLE IF NOT EXISTS permissions (
id SERIAL PRIMARY KEY,
created_at TIMESTAMP DEFAULT NOW(),
user_id UUID,
staff_function TEXT
)
35 changes: 35 additions & 0 deletions src/database.py
Original file line number Diff line number Diff line change
Expand Up @@ -835,4 +835,39 @@ def get_user_details_from_user_id(user_id):
result = cursor.fetchone()
cursor.close()
db_connection.close()
return result

def get_user_permissions(slack_user_id):
""" Gets users permissions from its slack user id."""
try:
db_connection = connect()
except exceptions.DatabaseConnectionError as ex:
log.critical("Couldn't get user permissions: {}".format(ex))
raise exceptions.QueryDatabaseError("Could not connect to database: {}".format(ex))
else:
cursor = db_connection.cursor()

sql_string = """
SELECT staff_function
FROM permissions
WHERE permissions.user_id IN (
SELECT users.user_id
FROM users
WHERE users.slack_id = %s
)
"""
data = (
slack_user_id,
)
try:
cursor.execute(sql_string, data)
except Exception as ex:
log.error("Couldn't get user details: {}".format(ex))
cursor.close()
db_connection.close()
raise exceptions.QueryDatabaseError("Could not perform database select query: {}".format(ex))
else:
result = cursor.fetchone()[0]
cursor.close()
db_connection.close()
return result
53 changes: 52 additions & 1 deletion src/dispatcher.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@
import string
import re
import uuid
import security


common.setup_logger()

Expand Down Expand Up @@ -59,6 +61,15 @@ def create_team_dispatcher(request):
log.debug("Create team request.")
team_name = request['text']

if not security.user_has_permission(security.RoleLevels.Admin, request["user_id"]):
log.error("User has no permission to execute this command.")
try:
database.save_request_log(request, False, "Unauthorized.")
except exceptions.SaveRequestLogError:
log.error("Failed to save request log on database.")
responder.unauthorized_error(request)
return

if not team_name:
log.warn("Bad format on command '{}': Not enough arguments."
.format(request['command'])
Expand Down Expand Up @@ -495,6 +506,16 @@ def list_teams_dispatcher(request):
"""Dispatcher to list teams requests/commands."""
log.debug("List teams request.")
# TODO: Change response to "No teams" if no teams were found.

if not security.user_has_permission(security.RoleLevels.Staff, request["user_id"]):
log.error("User has no permission to execute this command.")
try:
database.save_request_log(request, False, "Unauthorized.")
except exceptions.SaveRequestLogError:
log.error("Failed to save request log on database.")
responder.unauthorized_error(request)
return

try:
log.debug("Getting teams")
teams = database.get_teams()
Expand All @@ -519,6 +540,16 @@ def list_teams_registration_dispatcher(request):
"""Dispatcher to list teams registrations requests/commands."""
log.debug("List teams request.")
# TODO: Change response to "No teams" if no teams were found.

if not security.user_has_permission(security.RoleLevels.Staff, request["user_id"]):
log.error("User has no permission to execute this command.")
try:
database.save_request_log(request, False, "Unauthorized.")
except exceptions.SaveRequestLogError:
log.error("Failed to save request log on database.")
responder.unauthorized_error(request)
return

try:
log.debug("Getting teams registrations.")
teams = database.get_teams_registration()
Expand All @@ -542,6 +573,16 @@ def list_teams_registration_dispatcher(request):
def team_details_dispatcher(request):
"""Dispatcher to team details requests/commands."""
log.debug("Team details request.")

if not security.user_has_permission(security.RoleLevels.Staff, request["user_id"]):
log.error("User has no permission to execute this command.")
try:
database.save_request_log(request, False, "Unauthorized.")
except exceptions.SaveRequestLogError:
log.error("Failed to save request log on database.")
responder.unauthorized_error(request)
return

# Get team_id from args
team_id = request["text"]
if not team_id:
Expand Down Expand Up @@ -579,6 +620,16 @@ def team_details_dispatcher(request):
def user_details_dispatcher(request):
"""Dispatcher to user details requests/commands."""
log.debug("User details request.")

if not security.user_has_permission(security.RoleLevels.Staff, request["user_id"]):
log.error("User has no permission to execute this command.")
try:
database.save_request_log(request, False, "Unauthorized.")
except exceptions.SaveRequestLogError:
log.error("Failed to save request log on database.")
responder.unauthorized_error(request)
return

# Get user from args
args = get_request_args(request["text"])
if not args or len(args) > 1:
Expand Down Expand Up @@ -690,4 +741,4 @@ def check_valid_uuid4(arg):
log.warn("Invalid uuid4 format.")
return False
else:
return True
return True
15 changes: 15 additions & 0 deletions src/responder.py
Original file line number Diff line number Diff line change
Expand Up @@ -517,6 +517,21 @@ def unverified_origin_error():
}
return json.dumps(response_content, ensure_ascii=False).encode("utf-8")

def unauthorized_error(request):
"""Delayed response to Slack reporting no authorization."""
response_content = {
"text": "*NÃO PODES FAZER ISSO!*\nErro? Pede ajuda no <#{}|suporte>."
.format(get_support_channel_id()),
}
try:
if send_delayed_response(request['response_url'], response_content):
log.debug("Delayed message sent successfully.")
else:
log.critical("Delayed message not sent.")
except exceptions.POSTRequestError:
log.critical("Failed to send delayed message to Slack.")


def get_support_channel_id():
"""Get slack support channel id."""
return os.getenv("SLACK_SUPPORT_CHANNEL_ID")
Expand Down
35 changes: 35 additions & 0 deletions src/security.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import common
import database
import exceptions
import logging as log

common.setup_logger()

class RoleLevels:
Admin = "admin"
Staff = "staff"

role_level = {
"admin": 50,
"staff": 40
}

def user_has_permission(level, user):
""" Checks if a user has permissions to execute some operation."""
try:
user_permission = database.get_user_permissions(user)
except exceptions.QueryDatabaseError as ex:
log.error("Could not perform user permissions check: {}".format(ex))
return False
else:
log.debug(user_permission)
if not user_permission:
log.error("User doesn't have any permission.")
return False

if role_level[user_permission] >= role_level[level]:
log.debug("User has permission")
return True
else:
log.error("User doesn't have enough permission.")
return False

0 comments on commit 14c9732

Please sign in to comment.