Skip to content

Commit

Permalink
#60 #39 | Global Mentions, Encrypted Settings, Cleanup
Browse files Browse the repository at this point in the history
- Created Global Mentions Manager class

- Created Global Mention class

- Implemented Global Mentions Manager with Settings (Create/Update/Remove)

- Encrypted Pickling for the Global Mentions Manager setting.

- Added function settings for "get_setting_value" to help with security. Using the setting "deny_plaintext_setting" when retrieving setting value, objects will not re-pickle unless decryption is successful.

- Fixed the bug where S3 details couldn't be updated in the last commit, forgot to mention it

- Made it so that you cannot have duplicate global mention ids

- Added "encrypted_" prefix to settings. Automatically hidden & saved as encrypted on next setting change. Currently requires changing code to modify, might change this to allow users to define in app later on.

- Added Media Accounts, Supported Media Platforms, Global Mentions, Timezones, all S3 details, & more as encrypted_ settings.

- set_settings_value func now automatically encrypts setting values with the "encrypted_" prefix.

- Fixed a bug from last push that would decrypt encrypted values on update.
  • Loading branch information
VenomStyx committed Apr 25, 2022
1 parent cfd77e7 commit 8289fe7
Show file tree
Hide file tree
Showing 8 changed files with 597 additions and 262 deletions.
22 changes: 7 additions & 15 deletions resources/accounts.py
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ def load_data(self):
data_loaded = False

## Load Account Data from Settings
accounts = string_to_list_of_dictionaries(settings.get_setting_value("accounts", "media_accounts"))
accounts = string_to_list_of_dictionaries(settings.get_setting_value("accounts", "encrypted_media_accounts"))

for account in accounts:
if account["name"] == self.data['name']:
Expand Down Expand Up @@ -134,9 +134,9 @@ def register(self, display_name, key, secret, access_key=None, access_secret=Non
if accounts:
accounts.append(data)
# save new accounts
settings.write_encrypted_setting("accounts","media_accounts",str(accounts))
settings.set_setting_value("accounts","encrypted_media_accounts",str(accounts))
else:
settings.write_encrypted_setting("accounts","media_accounts",str([data]))
settings.set_setting_value("accounts","encrypted_media_accounts",str([data]))



Expand All @@ -156,7 +156,7 @@ def update(self, display_name=None, key=None, secret=None, access_key=None, acce
account["posting_locations"] = self.posting_location_to_string(posting_locations)
break
# save new accounts
settings.write_encrypted_setting("accounts","media_accounts",str(accounts))
settings.set_setting_value("accounts","encrypted_media_accounts",str(accounts))


########## REMOVE
Expand All @@ -175,9 +175,9 @@ def remove(self):

## Save New Accounts
if len(accounts) > 0:
settings.write_encrypted_setting("accounts","media_accounts",str(accounts))
settings.set_setting_value("accounts","encrypted_media_accounts",str(accounts))
else:
settings.set_setting_value("accounts","media_accounts","None")
settings.set_setting_value("accounts","encrypted_media_accounts","None")
print('account removed')

return True
Expand Down Expand Up @@ -317,15 +317,7 @@ def format_post_data(self, post_object):
content = f"**{post_object.title}**"
else:
content = f"**{post_object.title}**\n\n{post_object.description}"



# ##### PUT DATA TOGETHER
# post_data = {
# "content": content,
# #"allowed_mentions" : {"users": ["68751"] },
# }


return content


Expand Down
134 changes: 100 additions & 34 deletions resources/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,13 @@
import pathlib
import configparser
import ast
import pickle


from resources.crypt import Crypt, Key
from resources.utility import string_to_list_of_dictionaries
from resources.database import Storage

from resources.global_mentions import global_mentions_manager


# _ _ _ _ _
Expand Down Expand Up @@ -59,13 +60,13 @@ def __init__(self):
self.saved_path = str(self.current_path) + "saved/"

##### STORAGE
self.published_posts_file = cfg.get("storage","posts_file")
self.published_posts_file = cfg.get("storage","encrypted_posts_file")
self.published_posts_file_location = "saved/" + self.published_posts_file
self.published_posts_file_location_full = current_path + self.published_posts_file
self.scheduled_posts_file = cfg.get("storage","scheduled_posts_file")
self.scheduled_posts_file = cfg.get("storage","encrypted_scheduled_posts_file")
self.scheduled_posts_file_location = "saved/" + self.scheduled_posts_file
self.scheduled_posts_file_location_full = current_path + self.scheduled_posts_file # This needs to be changed for S3 support
self.uploaded_media_dir = cfg.get("storage","uploaded_media_dir")
self.uploaded_media_dir = cfg.get("storage","encrypted_uploaded_media_dir")
self.full_uploaded_media_dir = self.saved_path + self.uploaded_media_dir

##### ENCRYPTION
Expand All @@ -74,9 +75,11 @@ def __init__(self):

## Has encryption been setup?
if os.path.isfile(self.key_location):

# Yes, get key & block size
self.encryption_key = Key(self.key_location)
self.block_size = self.get_setting_value("encryption", "block_size")

# No, set block size
if str(self.block_size) == "None":
self.set_setting_value("encryption", "block_size", "4096")
Expand All @@ -93,36 +96,57 @@ def __init__(self):
print('user needs to setup initial key')


## Valid Encryption Key
########## ENCRYPTED
#####
if self.crypt_setup:

##### ACCOUNTS
media_accounts_temp = cfg.get("accounts","media_accounts")
media_accounts_temp = cfg.get("accounts","encrypted_media_accounts")
if media_accounts_temp != "None":
self.media_accounts = string_to_list_of_dictionaries(self.get_setting_value(category="accounts", setting="media_accounts"))
self.media_accounts = string_to_list_of_dictionaries(self.get_setting_value(category="accounts", setting="encrypted_media_accounts"))
else:
self.media_accounts = None

self.supported_media_platforms = cfg.get("accounts","encrypted_supported_media_platforms").split(",")

##### S3 CREDENTIALS
self.s3_access = self.get_setting_value(category="accounts", setting="hidden_s3_access")
self.s3_secret = self.get_setting_value(category="accounts", setting="hidden_s3_secret")
self.s3_endpoint = self.get_setting_value(category="accounts", setting="hidden_s3_endpoint")
self.s3_bucket = self.get_setting_value(category="accounts", setting="hidden_s3_bucket")
self.s3_access = self.get_setting_value(category="accounts", setting="encrypted_s3_access", deny_plaintext_setting=True)
self.s3_secret = self.get_setting_value(category="accounts", setting="encrypted_s3_secret", deny_plaintext_setting=True)
self.s3_endpoint = self.get_setting_value(category="accounts", setting="encrypted_s3_endpoint", deny_plaintext_setting=True)
self.s3_bucket = self.get_setting_value(category="accounts", setting="encrypted_s3_bucket", deny_plaintext_setting=True)

##### S3 SETUP
self.storage = Storage(self.s3_access, self.s3_secret, self.s3_endpoint, self.s3_bucket)


##### Global Mention IDs
self.global_mention_ids = ast.literal_eval(self.get_setting_value(category="posting", setting="global_mention_ids"))
##### GLOBAL MENTIONS
local_global_mentions = self.get_setting_value(category="posting", setting="encrypted_global_mentions", deny_plaintext_setting=True)

## No Current Global Manager
if local_global_mentions == "None": # No current setting,

## Create new Global Mentions Manager
self.global_mentions = global_mentions_manager()

## Write Manager to Settings
self.set_setting_value(category="posting", setting="encrypted_global_mentions", value=pickle.dumps(self.global_mentions))

## If Setting is invalid
elif not local_global_mentions:

## Couldn't Decrypt Setting
self.global_mentions = None

## Setting Valid
else:

## Load Global Mentions Manager Object
self.global_mentions = pickle.loads(ast.literal_eval(local_global_mentions))

else:
self.media_accounts = None
self.storage = None


self.supported_media_platforms = cfg.get("accounts","supported_media_platforms").split(",")


##### APPLICATION
self.no_posts_title = cfg.get("app","no_posts_title")
Expand All @@ -135,17 +159,17 @@ def __init__(self):
self.global_mentions_updated_message = cfg.get("app", "global_mentions_updated_message")

##### PERFORMANCE
self.posts_cache_time = float(cfg.get("performance","posts_cache_time"))
self.page_cache_time = float(cfg.get("performance","page_cache_time"))
self.posts_cache_time = float(cfg.get("performance","encrypted_posts_cache_time"))
self.page_cache_time = float(cfg.get("performance","encrypted_page_cache_time"))

##### MEDIA
self.supported_image_types = cfg.get("media","supported_image_types").split(",")
self.supported_video_types = cfg.get("media","supported_video_types").split(",")
self.supported_audio_types = cfg.get("media","supported_audio_types").split(",")
self.supported_image_types = cfg.get("media","encrypted_supported_image_types").split(",")
self.supported_video_types = cfg.get("media","encrypted_supported_video_types").split(",")
self.supported_audio_types = cfg.get("media","encrypted_supported_audio_types").split(",")

##### POSTING
self.utc_timezones = cfg.get("posting","utc_timezones").split(",")
self.default_timezone = cfg.get("posting","default_timezone")
self.utc_timezones = cfg.get("posting","encrypted_utc_timezones").split(",")
self.default_timezone = cfg.get("posting","encrypted_default_timezone")



Expand All @@ -154,19 +178,27 @@ def reload_config(self):


def read_encrypted_setting(self, setting_value):
"""
Decrypts an input setting value. Does not read from file, you can input any encrypted value.
Rejects Plaintext & Failed Decryptions by returning None if input & output are the same.
"""
try:
## Decrypt
return self.crypt.decrypt(setting_value.encode()).decode()
except Exception as e:
print(e)
## Decryption Failed
return None

def write_encrypted_setting(self, category, setting, value):


def set_setting_value(self, category, setting, value):
try:
value = self.crypt.encrypt(str(value).encode())
self.set_setting_value(category, setting, value.decode())
self.reload_config()
except Exception as e:
print(e)
print(f"Exception while running set_encrypted_value: {str(e)}")
return None

########## GET ALL SETTINGS CATEGORIES
Expand Down Expand Up @@ -211,7 +243,7 @@ def get_all_settings_in_category(self,category):

########## GET SETTING VALUE
#####
def get_setting_value(self,category=None,setting=None):
def get_setting_value(self,category=None,setting=None, auto_decrypt=True, deny_encrypted_setting=False, deny_plaintext_setting=False):

## If no setting provided, return None
if setting == None:
Expand All @@ -223,11 +255,46 @@ def get_setting_value(self,category=None,setting=None):

## Get setting value
value = cfg.get(category,setting)

## Decrypt if encrypted
if list(value)[-1] == "=":
value = self.read_encrypted_setting(value)

## Flag Initial Values
if value == "None":
return "None"

## Check if encrypted
if setting.startswith("encrypted_"):

## Try to decrypt the value. If not none, it's encrypted.
decrypted_value = self.read_encrypted_setting(value)

## Valid encrypted setting
if decrypted_value:

## Value encrypted when shouldn't be
if deny_encrypted_setting == False:

## Auto Decrypt
if auto_decrypt:
value = decrypted_value

## Deny Encrypted Setting if Found
else:
return None

## If value is plaintext
else:

## Value already decrypted. Assuming tampering
if deny_plaintext_setting==True:
return None

## Value already decrypted. Assuming default values
else:
return value

## Deny Plaintext if Found
elif deny_plaintext_setting:
return None

return value


Expand All @@ -245,7 +312,8 @@ def set_setting_value(self,category=None,setting=None,value=None):
category = self.get_setting_category(setting)

## Encrypt if encrypted (soon)

if setting.startswith("encrypted_"):
value = self.crypt.encrypt(str(value).encode()).decode()

## Set setting value
cfg.set(category,setting,value)
Expand Down Expand Up @@ -294,8 +362,6 @@ def get_media_accounts_with_names(self, names):





class server_settings:

def __init__(self):
Expand Down

0 comments on commit 8289fe7

Please sign in to comment.