Commit 4f3204df authored by Shashank Kumar's avatar Shashank Kumar

Encryption tools services added

- Adds create key pair module
parents 1375b343 d6b46042
# Project directories
modules/encryption/tools/all_tools/gnupg_home
/libs
# Python
*.pyc
......
......@@ -5,13 +5,16 @@ before_script:
- apt-get update -qy
- apt-get install -y python3 python3-dev python3-pip build-essential ffmpeg libsdl2-dev libsdl2-image-dev libsdl2-mixer-dev libsdl2-ttf-dev libportmidi-dev libswscale-dev libavformat-dev libavcodec-dev zlib1g-dev
- apt-get install -y libgstreamer1.0 gstreamer1.0-plugins-base gstreamer1.0-plugins-good
- apt-get install ffmpeg
- apt-get install -y ffmpeg git
- pip3 install pipenv
- pipenv install --dev --skip-lock
- pipenv install --skip-lock
- pipenv install --skip-lock git+http://github.com/kivy/kivy.git#egg=kivy-1.10.1
pylint:
type: test
script:
- pipenv install --skip-lock pylint
- pipenv run pylint main
- pipenv run pylint settings
- pipenv run pylint modules
......@@ -19,5 +22,6 @@ pylint:
pytest:
type: test
script:
- pipenv run pytest tests
- pipenv run pytest --cov=modules
- apt-get install -y gnupg
- pipenv install --skip-lock pytest pytest-cov
- pipenv run pytest tests --cov=modules
......@@ -54,7 +54,8 @@ confidence=
# --enable=similarities". If you want to run only the classes checker, but have
# no Warning level messages displayed, use"--disable=all --enable=classes
# --disable=W"
disable=pointless-string-statement,
disable=duplicate-code,
pointless-string-statement,
useless-super-delegation,
parameter-unpacking,
unpacking-in-except,
......
......@@ -10,7 +10,7 @@ pytest-cov = "==2.5.1"
[packages]
cython = "==0.28"
"kivy-1.10.1" = {path = "git+http://github.com/kivy/kivy.git"}
python-gnupg = "==0.4.3"
[requires]
python_version = "3.5"
{
"_meta": {
"hash": {
"sha256": "be7a68baefde5ad055728aa020a19d72aa1668836334ad398492e2b87f75879a"
"sha256": "eaa221d475af278cb4318daa3598a2c329c33d2c1fd7b220f7d4e60f4ba422c7"
},
"pipfile-spec": 6,
"requires": {
......@@ -51,6 +51,14 @@
],
"index": "pypi",
"version": "==0.28"
},
"python-gnupg": {
"hashes": [
"sha256:2d158dfc6b54927752b945ebe57e6a0c45da27747fa3b9ae66eccc0d2147ac0d",
"sha256:faa69bab58ed0936f0ccf96c99b92369b7a1819305d37dfe5c927d21a437a09d"
],
"index": "pypi",
"version": "==0.4.3"
}
},
"develop": {
......@@ -183,10 +191,10 @@
},
"py": {
"hashes": [
"sha256:29c9fab495d7528e80ba1e343b958684f4ace687327e6f789a94bf3d1915f881",
"sha256:983f77f3331356039fdd792e9220b7b8ee1aa6bd2b25f567a963ff1de5a64f6a"
"sha256:3fd59af7435864e1a243790d322d763925431213b6b8529c6ca71081ace3bbf7",
"sha256:e31fb2767eb657cbde86c454f02e99cb846d3cd9d61b318525140214fdc0e98e"
],
"version": "==1.5.3"
"version": "==1.5.4"
},
"pylint": {
"hashes": [
......
v0.0.1
## June 7 2018
- Sign Up feature added.
## June 11 2018
- Adding Dashboard feature
- Adding blog, cli, communication, encryption, how_to_use, vcs and way_ahead modules for courseware
- Adding application, profile and theme modules for settings
## June 7 2018
## June 11 2018
- Adding Dashboard feature
- Adding blog, cli, communication, encryption, how_to_use, vcs and way_ahead modules for courseware
- Adding application, profile and theme modules for settings
- Sign Up feature added.
## June 3 2018
......
[
{"application_settings": 1},
{"blog": 1},
{"cli": 1},
{"communication": 1},
{"encryption":[
{
"tutorials": 0
},
{
"tools": [
{
"Create and manage key pair": {
"difficulty": "Beginner"
},
"Encrypt a message": {
"difficulty": "Intermediate"
},
"Decrypt a message": {
"difficulty": "Intermediate"
},
"Sign other keys": {
"difficulty": "Advance"
}
}
]
}
]
},
{"how_to_use": 1},
{"profile_settings": 1},
{"theme_settings": 1},
{"vcs": 1},
{"way_ahead": 1}
]
\ No newline at end of file
{"application_settings": 1},
{"blog": 1},
{"cli": 1},
{"communication": 1},
{"encryption":[
{
"tutorials": 0
},
{
"tools": [
{
"Display and manage key pair": {
"difficulty": "Beginner"
},
"Create key pair": {
"difficulty": "Beginner"
},
"Encrypt a message": {
"difficulty": "Intermediate"
},
"Decrypt a message": {
"difficulty": "Intermediate"
}
}
]
}
]
},
{"how_to_use": 1},
{"profile_settings": 1},
{"theme_settings": 1},
{"vcs": 1},
{"way_ahead": 1}
]
......@@ -3,10 +3,11 @@ Root Kivy Application
'''
from kivy.app import App
from kivy.config import Config
from kivy.uix.screenmanager import ScreenManager
from settings import initializing_database
from modules.signup.signup import SignUp
from modules.dashboard.dashboard import Dashboard
from modules.signup import signup
from modules.dashboard import dashboard
class NewContributorWizard(App):
......@@ -14,8 +15,15 @@ class NewContributorWizard(App):
Declaration of Root Kivy App which contains Root Widget
'''
def __init__(self, **kwargs):
super().__init__(**kwargs)
self.screen_manager_obj = ScreenManager()
self.screen_manager_obj.add_widget(signup.SignUp(name='signup'))
self.screen_manager_obj.add_widget(dashboard.Dashboard(name='dashboard'))
def build(self):
self.load_kv('./ui/main.kv')
return self.screen_manager_obj
if __name__ == '__main__':
'''
......@@ -25,6 +33,7 @@ if __name__ == '__main__':
'''
Fixing touch issue with some platforms
Setting window width to 720px and height to 480px
'''
Config.set('input', 'mouse', 'mouse')
......
......@@ -26,6 +26,7 @@ class Dashboard(BoxLayout, Screen):
'''
Dashboard class to integrate courseware and settings
'''
def __init__(self, **kwargs):
super().__init__(**kwargs)
self.all_menu_screens = {
......@@ -41,27 +42,26 @@ class Dashboard(BoxLayout, Screen):
'way_ahead': WayAhead(),
}
self.all_menu_items = list(self.all_menu_screens.keys())
self.enable_menu('cli')
self.enable_menu('encryption')
def enable_menu(self, menu_item_to_enable):
'''
enable_menu function focuses on concerned menu items or settings which is clicked and
removes focus from all other menu items and settings
'''
menu_item_to_enable_widget = self.ids[menu_item_to_enable+'_box']
menu_item_to_enable_widget = self.ids[menu_item_to_enable + '_box']
menu_item_to_enable_color = menu_item_to_enable_widget.canvas.before.children[0].rgba
if menu_item_to_enable_color != [1, 1, 1, 1] or 'settings' in menu_item_to_enable:
self.ids['module_screen'].add_widget(self.all_menu_screens[menu_item_to_enable])
if 'settings' not in menu_item_to_enable:
self.ids[menu_item_to_enable+'_box'].canvas.before.children[0].rgba = [1, 1, 1, 1]
self.ids[menu_item_to_enable+'_label'].color = (0, 0, 0, 1)
self.ids[menu_item_to_enable + '_box'].canvas.before.children[0].rgba = [1, 1, 1, 1]
self.ids[menu_item_to_enable + '_label'].color = (0, 0, 0, 1)
all_menu_items_copy = cp(self.all_menu_items)
all_menu_items_copy.remove(menu_item_to_enable)
for menu_item in all_menu_items_copy:
if 'settings' not in menu_item:
self.ids[menu_item+'_box'].canvas.before.children[0].rgba = [0, 0, 0, 1]
self.ids[menu_item+'_label'].color = (1, 1, 1, 1)
self.ids[menu_item + '_box'].canvas.before.children[0].rgba = [0, 0, 0, 1]
self.ids[menu_item + '_label'].color = (1, 1, 1, 1)
self.ids['module_screen'].remove_widget(self.all_menu_screens[menu_item])
......@@ -12,10 +12,12 @@ from modules.encryption.tools import tools
Builder.load_file('./ui/encryption/encryption.kv')
class Encryption(BoxLayout):
'''
Encryption class for tutorials and tools
'''
def __init__(self, **kwargs):
super(Encryption, self).__init__(**kwargs)
self.all_options = {
......@@ -25,23 +27,22 @@ class Encryption(BoxLayout):
self.all_options_items = list(self.all_options.keys())
self.enable_option('tools')
def enable_option(self, option_to_enable):
'''
enable_menu function focuses on concerned menu items or settings which is clicked and
removes focus from all other menu items and settings
'''
option_to_enable_widget = self.ids[option_to_enable+'_box']
option_to_enable_widget = self.ids[option_to_enable + '_box']
option_to_enable_color = option_to_enable_widget.canvas.before.children[0].rgba
if option_to_enable_color != [1, 1, 1, 1]:
self.ids[option_to_enable+'_box'].canvas.before.children[0].rgba = [1, 1, 1, 1]
self.ids[option_to_enable + '_box'].canvas.before.children[0].rgba = [1, 1, 1, 1]
self.ids[option_to_enable].color = (0, 0, 0, 1)
all_options_items_copy = cp(self.all_options_items)
all_options_items_copy.remove(option_to_enable)
for option in all_options_items_copy:
self.ids[option+'_box'].canvas.before.children[0].rgba = [0, 0, 0, 1]
self.ids[option + '_box'].canvas.before.children[0].rgba = [0, 0, 0, 1]
self.ids[option].color = (1, 1, 1, 1)
self.ids['encryption_content_box'].remove_widget(self.all_options[option])
......
'''
This modules helps display and manage key pairs
'''
import logging
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.label import Label
from kivy.uix.button import Button
from kivy.lang import Builder
from kivy.clock import Clock
from kivy.uix.popup import Popup
from modules.encryption.tools.all_tools.exceptions import GPGError
from modules.encryption.tools.all_tools.services import create_key_pair as ckp
from modules.encryption.tools.all_tools.validations import (
validate_email,
validate_name,
validate_comment,
validate_expire_date
)
Builder.load_file('./ui/encryption/all_tools/create_key_pair.kv')
class CreateKeyPair(BoxLayout):
'''
CreateKeyPair helps integrate UI with helper functions
'''
def prompt_error_message(self, label, error_text):
'''
Displays error message on the UI on the respective label widget
'''
original_text = self.ids[label].text
self.ids[label].text = error_text
self.ids[label].color = [1, 0, 0, 1]
def replace_label(*args):
'''
Replacing original text in label
delay time is defined by args[0]
'''
logging.info(
'\'%s\' changed to \'%s\' after %s seconds',
error_text,
original_text,
args[0]
)
self.ids[label].text = original_text
self.ids[label].color = [1, 1, 1, 1]
Clock.schedule_once(replace_label, 2)
def validate(self):
'''
Validating user input
'''
name = self.ids['input_name'].text
email = self.ids['input_email'].text
comment = self.ids['input_comment'].text
expire_date = self.ids['input_expire_date'].text
validation_successful = True
try:
validate_name(name)
except GPGError as error:
validation_successful = False
self.prompt_error_message(
'label_name',
error.message
)
try:
validate_email(email)
except GPGError as error:
validation_successful = False
self.prompt_error_message(
'label_email',
error.message
)
try:
validate_comment(comment)
except GPGError as error:
validation_successful = False
self.prompt_error_message(
'label_comment',
error.message
)
try:
validate_expire_date(expire_date)
except GPGError as error:
validation_successful = False
self.prompt_error_message(
'label_expire_date',
error.message
)
return validation_successful
def create_key_pair(self):
'''
Processing user input to create key pair
'''
content_for_popup = BoxLayout(size_hint=(1, 0.8))
content_for_popup.add_widget(Label(text='Key creation in progress'))
popup = Popup(title='Test popup', content=content_for_popup,
auto_dismiss=False, size_hint=(None, None), size=(400, 300))
popup.children[0].children[0].orientation = 'vertical'
popup.children[0].children[0].add_widget(BoxLayout(size_hint=(1, 0.2)))
def add_button(*args):
'''
Replace original popup text and add button
'''
popup.children[0].children[0].children[1].children[0].text = args[0]
popup.children[0].children[0].children[0].add_widget(
Button(text='Okay', on_press=popup.dismiss)
)
if self.validate():
name = self.ids['input_name'].text
email = self.ids['input_email'].text
comment = self.ids['input_comment'].text
expire_date = self.ids['input_expire_date'].text
try:
popup.open()
key_fingerprint = ckp(
name=name,
email=email,
comment=comment,
expire_date=expire_date
)
message = 'Key has been created with\n{}\nfingerprint'.format(
key_fingerprint)
add_button(message)
except GPGError as error:
add_button(error.message)
'''
This modules helps create and manage key pairs
This modules helps display and manage key pairs
'''
from kivy.uix.boxlayout import BoxLayout
from kivy.lang import Builder
Builder.load_file('./ui/encryption/all_tools/create_and_manage_key_pair.kv')
Builder.load_file('./ui/encryption/all_tools/display_and_manage_key_pair.kv')
class CreateAndManageKeyPair(BoxLayout):
class DisplayAndManageKeyPair(BoxLayout):
'''
CreateAndManageKeyPair helps integrate UI with helper functions
DisplayAndManageKeyPair helps integrate UI with helper functions
'''
pass
'''
Exceptions module contains exception classes specific to encryption.tools module
'''
class GPGError(Exception):
'''
GPGError class can be used to raise exception related to
User's imput
'''
def __init__(self, message):
self.message = message
super().__init__(message)
'''
Service functions for encryption.tools module
'''
import gnupg
from modules.encryption.tools.all_tools.exceptions import GPGError
GNUPG_HOME = 'modules/encryption/tools/all_tools/gnupg_home'
def create_gnupg_object():
'''
Creating and returning GnuPG object
'''
gpg = gnupg.GPG(gnupghome=GNUPG_HOME)
gpg.encoding = 'utf-8'
return gpg
def create_key_pair(name, email, comment, expire_date, passphrase=''):
'''
Creating fresh public and private keys and returning key's fingerprint
'''
gpg = create_gnupg_object()
key_length = 1024
key_type = 'RSA'
input_data = gpg.gen_key_input(
key_length=key_length,
key_type=key_type,
name_real=name,
name_comment=comment,
name_email=email,
expire_date=expire_date,
passphrase=passphrase
)
key = gpg.gen_key(input_data)
if key.fingerprint:
return key.fingerprint
else:
raise GPGError(message=getattr(key, 'stderr'))
def list_all_keys():
'''
Returning all public and private keys available in keyring
'''
gpg = create_gnupg_object()
return {
'all_public_keys': gpg.list_keys().key_map,
'all_private_keys': gpg.list_keys(True).key_map
}
def export_single_key(keyid, passphrase=None):
'''
Returning public or private key in ascii format
'''
gpg = create_gnupg_object()
if passphrase:
return gpg.export_keys(keyid, True, passphrase=passphrase)
return gpg.export_keys(keyid)
def encrypt_message(keyid, message):
'''
Encrypting a message using a public key
'''
gpg = create_gnupg_object()
encrypted_message_object = gpg.encrypt(message, keyid)
if encrypted_message_object.ok:
return str(encrypted_message_object)
else:
raise GPGError(message=encrypted_message_object.status)
def decrypt_message(message, passphrase):
'''
Decrypting a message using private key and passphrase
'''
gpg = create_gnupg_object()
decrypted_message_object = gpg.decrypt(message, passphrase=passphrase)
if decrypted_message_object.ok:
return str(decrypted_message_object)
else:
raise GPGError(message=decrypted_message_object.status)
'''
This module helps user sign other keys with existing key pair
'''
from kivy.uix.boxlayout import BoxLayout
from kivy.lang import Builder
Builder.load_file('./ui/encryption/all_tools/sign_other_keys.kv')
class SignOtherKeys(BoxLayout):
'''
SignOtherKeys integrated UI with helper functions
'''
pass
'''
Utility functions for encryption.tools module
'''
def clean_email(user_email):
'''
clean_email removes unnecessary spaces from Full Name
'''
return user_email.strip('\t\n\r ')
def clean_name(name):
'''
clean_name removes unnecessary spaces from Full Name
'''
name = ' '.join(name.split())
return name.strip('\t\n\r ')
'''
Validation functions for encryption.tools module
'''
import re
from datetime import datetime as dt
from modules.encryption.tools.all_tools.exceptions import GPGError
from modules.encryption.tools.all_tools.utils import (
clean_email,
clean_name)
def validate_name(name):
'''
Validating whether Full Name is provided by user and is in
correct alphabet format
'''
cleaned_name = clean_name(name)
if not cleaned_name:
raise GPGError('Enter Full Name')
for part_name in cleaned_name.split():
if not part_name.isalpha():
raise GPGError('Incorrect Format')
return True
def validate_email(email):
'''
Validating Email provided to check for proper mail format and
only alphabets
'''
cleaned_email = clean_email(email)
if not re.match(r'[^@]+@[^@]+\.[^@]+', cleaned_email):
raise GPGError('Incorrect Format')
cleaned_email = cleaned_email.strip(' ').split('.')
for parts in cleaned_email:
parts = parts.split('@')
if not all(part.isalpha() for part in parts):
raise GPGError('Incorrect Format')
return True
def validate_comment(comment):
'''
Validating comment provided by the user for any unnecessary symbols
'''
if not comment:
raise GPGError('Enter Comment')
for part_comment in comment.split():
if not part_comment.isalpha():
raise GPGError('Incorrect Format')
return True
def validate_expire_date(date):
'''
Validating date for correct format from one of the following
YYYY-MM-DD
'''
if not re.match(r'(\d){4}-(\d){2}-(\d){2}', date):
raise GPGError('Invalid Format')
try:
datetime_object = dt.strptime(date, '%Y-%m-%d')
except ValueError:
raise GPGError('Invalid Format')
if datetime_object < dt.now():
raise GPGError('Date should be of future')
return True
......@@ -29,6 +29,7 @@ class Tools(BoxLayout):
'''
Tools class to present Tools menu of Encryption
'''
def __init__(self, **kwargs):
super(Tools, self).__init__(**kwargs)
......@@ -57,8 +58,6 @@ class Tools(BoxLayout):
'Advance': (0.890, 0.090, 0.039, 1),
}
count_widgets = 0
for key, value in self.all_tools.items():
tool_title = value['title']
tool_difficulty = value["difficulty"]
......@@ -79,7 +78,7 @@ class Tools(BoxLayout):
'''
module_name = tool_to_import
class_name = ''.join(tool_to_import.title().split('_'))
tool_module = import_module('modules.encryption.tools.all_tools.'+module_name)
tool_module = import_module('modules.encryption.tools.all_tools.' + module_name)
tool_class = getattr(tool_module, class_name)
self.all_tools[tool_to_import]['module'] = tool_module
self.all_tools[tool_to_import]['class'] = tool_class
......
......@@ -33,6 +33,7 @@ class SignUp(BoxLayout, Screen):
original_text = self.ids[label].text
self.ids[label].text = error_text
self.ids[label].color = (255, 0, 0, 1)
def replace_label(*args):
'''
Replacing original text in label
......@@ -103,7 +104,6 @@ class SignUp(BoxLayout, Screen):