PyCyphORM 0.1.3__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,54 @@
1
+ Metadata-Version: 2.1
2
+ Name: PyCyphORM
3
+ Version: 0.1.3
4
+ Summary: A Minimalistic SQLite InMemory Encrypted ORM
5
+ Author: jafrmartins
6
+ Author-email: j.afr.martins@outlook.pt
7
+ Keywords: sqlite encrypted inmemory orm
8
+ Description-Content-Type: text/markdown
9
+
10
+ # PyCyphOrm
11
+
12
+ A Minimalistic SQLite InMemory Encrypted ORM
13
+
14
+ ## Usage
15
+
16
+ ### Command Line Interface
17
+
18
+ ```sh
19
+ usage: PyCyphORM [-h] [-i INIT] [-d FILEPATH]
20
+
21
+ A Minimalistic SQLite InMemory Encrypted ORM
22
+
23
+ options:
24
+ -h, --help show this help message and exit
25
+ -i INIT, --init INIT Initialize Salt and Password for
26
+ Encrypted Database
27
+ -d FILEPATH, --decrypt FILEPATH
28
+ Descrypt SQLite Database
29
+ ```
30
+
31
+ ### Example
32
+
33
+ ```python
34
+
35
+ from PyCyphORM.lib import load_config, ORM
36
+
37
+ cnf = load_config(".pyorm")
38
+ orm = ORM.instance(".cache", cnf["PASSWORD"], cnf["SALT"], {
39
+ "Note": {
40
+ "id": "INTEGER PRIMARY KEY AUTOINCREMENT",
41
+ "title": "TEXT NOT NULL",
42
+ "description": "TEXT NOT NULL",
43
+
44
+ }
45
+ })
46
+
47
+ orm.model("Note").insert({
48
+ "title": "Your Title #1",
49
+ "description": "Your Descriptioj #2",
50
+ })
51
+
52
+ orm.save()
53
+
54
+ ```
@@ -0,0 +1,54 @@
1
+ Metadata-Version: 2.1
2
+ Name: PyCyphORM
3
+ Version: 0.1.3
4
+ Summary: A Minimalistic SQLite InMemory Encrypted ORM
5
+ Author: jafrmartins
6
+ Author-email: j.afr.martins@outlook.pt
7
+ Keywords: sqlite encrypted inmemory orm
8
+ Description-Content-Type: text/markdown
9
+
10
+ # PyCyphOrm
11
+
12
+ A Minimalistic SQLite InMemory Encrypted ORM
13
+
14
+ ## Usage
15
+
16
+ ### Command Line Interface
17
+
18
+ ```sh
19
+ usage: PyCyphORM [-h] [-i INIT] [-d FILEPATH]
20
+
21
+ A Minimalistic SQLite InMemory Encrypted ORM
22
+
23
+ options:
24
+ -h, --help show this help message and exit
25
+ -i INIT, --init INIT Initialize Salt and Password for
26
+ Encrypted Database
27
+ -d FILEPATH, --decrypt FILEPATH
28
+ Descrypt SQLite Database
29
+ ```
30
+
31
+ ### Example
32
+
33
+ ```python
34
+
35
+ from PyCyphORM.lib import load_config, ORM
36
+
37
+ cnf = load_config(".pyorm")
38
+ orm = ORM.instance(".cache", cnf["PASSWORD"], cnf["SALT"], {
39
+ "Note": {
40
+ "id": "INTEGER PRIMARY KEY AUTOINCREMENT",
41
+ "title": "TEXT NOT NULL",
42
+ "description": "TEXT NOT NULL",
43
+
44
+ }
45
+ })
46
+
47
+ orm.model("Note").insert({
48
+ "title": "Your Title #1",
49
+ "description": "Your Descriptioj #2",
50
+ })
51
+
52
+ orm.save()
53
+
54
+ ```
@@ -0,0 +1,12 @@
1
+ README.md
2
+ setup.py
3
+ PyCyphORM.egg-info/PKG-INFO
4
+ PyCyphORM.egg-info/SOURCES.txt
5
+ PyCyphORM.egg-info/dependency_links.txt
6
+ PyCyphORM.egg-info/entry_points.txt
7
+ PyCyphORM.egg-info/top_level.txt
8
+ src/PyCyphORM/__init__.py
9
+ src/PyCyphORM/cli.py
10
+ src/PyCyphORM/lib/__init__.py
11
+ src/PyCyphORM/lib/adapter.py
12
+ src/PyCyphORM/lib/orm.py
@@ -0,0 +1,2 @@
1
+ [console_scripts]
2
+ pycyphorm = cli:cli
@@ -0,0 +1 @@
1
+ PyCyphORM
@@ -0,0 +1,45 @@
1
+ # PyCyphOrm
2
+
3
+ A Minimalistic SQLite InMemory Encrypted ORM
4
+
5
+ ## Usage
6
+
7
+ ### Command Line Interface
8
+
9
+ ```sh
10
+ usage: PyCyphORM [-h] [-i INIT] [-d FILEPATH]
11
+
12
+ A Minimalistic SQLite InMemory Encrypted ORM
13
+
14
+ options:
15
+ -h, --help show this help message and exit
16
+ -i INIT, --init INIT Initialize Salt and Password for
17
+ Encrypted Database
18
+ -d FILEPATH, --decrypt FILEPATH
19
+ Descrypt SQLite Database
20
+ ```
21
+
22
+ ### Example
23
+
24
+ ```python
25
+
26
+ from PyCyphORM.lib import load_config, ORM
27
+
28
+ cnf = load_config(".pyorm")
29
+ orm = ORM.instance(".cache", cnf["PASSWORD"], cnf["SALT"], {
30
+ "Note": {
31
+ "id": "INTEGER PRIMARY KEY AUTOINCREMENT",
32
+ "title": "TEXT NOT NULL",
33
+ "description": "TEXT NOT NULL",
34
+
35
+ }
36
+ })
37
+
38
+ orm.model("Note").insert({
39
+ "title": "Your Title #1",
40
+ "description": "Your Descriptioj #2",
41
+ })
42
+
43
+ orm.save()
44
+
45
+ ```
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,27 @@
1
+ import os
2
+ import setuptools
3
+
4
+ # pip install ./PyORM --upgrade -t /home/jam/.local/lib/python3.10/site-packages/PyORM
5
+
6
+ readme = open("%s%sREADME.md"%(os.path.dirname(__file__), os.path.sep)).read()
7
+
8
+
9
+ setuptools.setup(
10
+ name='PyCyphORM',
11
+ version='0.1.3',
12
+ author='jafrmartins',
13
+ keywords='sqlite encrypted inmemory orm',
14
+ author_email='j.afr.martins@outlook.pt',
15
+ description='A Minimalistic SQLite InMemory Encrypted ORM',
16
+ packages=setuptools.find_packages('src'),
17
+ install_requires=[],
18
+ package_dir={'PyCyphORM': 'src/PyCyphORM', },
19
+ entry_points={
20
+ 'console_scripts': [
21
+ 'pycyphorm=cli:cli',
22
+ ],
23
+ },
24
+ include_package_data=True,
25
+ long_description=readme,
26
+ long_description_content_type='text/markdown'
27
+ )
@@ -0,0 +1,3 @@
1
+ from .lib.adapter import load_config
2
+ from .lib.orm import ORM
3
+ from .cli import cli
@@ -0,0 +1,45 @@
1
+ #!/bin/env python3
2
+
3
+ import argparse
4
+
5
+ from os import urandom, path
6
+ from base64 import b16encode
7
+ import random
8
+
9
+ import json
10
+
11
+ def random_password():
12
+ password = ""
13
+ characters = "abcdefghijklmnopqrstuvxyz0123456789~/|#$%&()"
14
+ for index in range(12):
15
+ password = password + random.choice(characters)
16
+ return password
17
+
18
+ parser = argparse.ArgumentParser(
19
+ prog = 'PyCyphORM',
20
+ description = 'A Minimalistic SQLite InMemory Encrypted ORM',
21
+ )
22
+
23
+ parser.add_argument("-i", "--init", metavar="INIT", help="Initialize Salt and Password for Encrypted Database")
24
+ parser.add_argument("-d", "--decrypt", metavar="FILEPATH", help="Descrypt SQLite Database")
25
+ #parser.add_argument("output", metavar="DEST", default=".", help="Destination Folder")
26
+
27
+ def cli():
28
+ args = vars(parser.parse_args())
29
+ if args["init"]:
30
+ with open(".pyorm", "w") as f:
31
+ f.write(json.dumps({
32
+ "SALT": b16encode(urandom(16)).decode("utf-8"),
33
+ "PASSWORD": b16encode(bytes(random_password(), "utf-8")).decode("utf-8")
34
+ }))
35
+
36
+ elif args['decrypt']:
37
+ if path.exists(path.abspath(args['decrypt'])):
38
+
39
+ from .lib.adapter import decrypt_cdb, load_config
40
+
41
+ cnf = load_config(".pyorm")
42
+ decrypt_cdb(path.abspath(args['decrypt']), cnf["PASSWORD"], cnf["SALT"])
43
+
44
+
45
+ if __name__ == "__main__": cli()
@@ -0,0 +1,2 @@
1
+ from .adapter import load_config
2
+ from .orm import ORM
@@ -0,0 +1,68 @@
1
+ from cryptography.fernet import Fernet
2
+ from cryptography.hazmat.primitives.kdf.pbkdf2 import PBKDF2HMAC
3
+ from cryptography.hazmat.primitives import hashes
4
+ from cryptography.hazmat.backends import default_backend
5
+ import json
6
+
7
+ import sqlite3
8
+ import gzip
9
+ import os
10
+
11
+ from base64 import b16decode, urlsafe_b64encode
12
+
13
+ def load_config(filepath):
14
+ config = None
15
+ with open(filepath, "rb") as f:
16
+ config = json.loads(f.read())
17
+ for key in config:
18
+ if isinstance(config[key], str):
19
+ config[key] = b16decode(config[key])
20
+ return config
21
+
22
+ def key_creation(password, salt):
23
+ kdf=PBKDF2HMAC(algorithm = hashes.SHA256(), salt=salt, iterations=1024, length=32, backend=default_backend())
24
+ key=Fernet(urlsafe_b64encode(kdf.derive(password)))
25
+ return key
26
+
27
+ def encryption(b, password, salt):
28
+ f=key_creation(password, salt)
29
+ safe=f.encrypt(b)
30
+ return safe
31
+
32
+ def decryption(safe, password, salt):
33
+ f=key_creation(password, salt)
34
+ b=f.decrypt(safe)
35
+ return b
36
+
37
+ def open_cdb(filename, password, salt):
38
+ if not os.path.exists(filename):
39
+ con = sqlite3.connect(':memory:')
40
+ return con
41
+ f=gzip.open(filename,'rb')
42
+ safe=f.read()
43
+ f.close()
44
+ content=decryption(safe,password,salt)
45
+ content=content.decode('utf-8')
46
+ con=sqlite3.connect(':memory:')
47
+ con.executescript(content)
48
+ return con
49
+
50
+ def decrypt_cdb(filename, password, salt):
51
+ f=gzip.open(filename,'rb')
52
+ safe=f.read()
53
+ f.close()
54
+ content=decryption(safe,password,salt)
55
+ fp=gzip.open(filename+".decoded.db",'wb')
56
+ fp.write(content)
57
+ fp.close()
58
+
59
+ def save_cdb(con, filename, password, salt):
60
+ fp=gzip.open(filename,'wb')
61
+ b=b''
62
+ for line in con.iterdump():
63
+ b+=bytes('%s\n','utf8') % bytes(line,'utf8')
64
+ b=encryption(b,password, salt)
65
+ fp.write(b)
66
+ fp.close()
67
+
68
+
@@ -0,0 +1,175 @@
1
+ from .adapter import open_cdb, save_cdb
2
+ import os
3
+
4
+ class QueryBuilder:
5
+
6
+ @staticmethod
7
+ def __where__(clause):
8
+ where = []
9
+ for k in clause:
10
+ if clause[k] == None:
11
+ where.append("%s IS NULL" % (k))
12
+ else:
13
+ where.append("%s = \"%s\"" % (k, clause[k]))
14
+ return ",".join(where)
15
+
16
+ @staticmethod
17
+ def __set__(clause):
18
+ st = []
19
+ for k in clause:
20
+ if clause[k] == None:
21
+ st.append("%s = NULL" % (k))
22
+ else:
23
+ st.append("%s = \"%s\"" % (k, clause[k]))
24
+ return ",".join(st)
25
+
26
+ @staticmethod
27
+ def __insert__(table, data):
28
+ if isinstance(data, dict):
29
+ columns = []
30
+ values = []
31
+ for column in data:
32
+ columns.append(column)
33
+ values.append("\"%s\"" % data[column])
34
+ sql = "INSERT INTO %s (%s) VALUES (%s)" % (table, ",".join(columns), ",".join(values))
35
+ else:
36
+ count = 0
37
+ columns = []
38
+ bulk = []
39
+ for row in data:
40
+ values = []
41
+ for column in row:
42
+ if count == 0:
43
+ columns.append(column)
44
+ values.append("\"%s\"" % data[column])
45
+ count += 1
46
+ bulk.append("(%s)" % (",".join(values)))
47
+ sql = "INSERT INTO %s (%s) VALUES %s" % (table, ",".join(columns), ",".join(bulk))
48
+ return sql
49
+
50
+ @staticmethod
51
+ def __create_table__(table, schema):
52
+ definition = []
53
+ for column in schema:
54
+ definition.append("%s %s" % (column, schema[column]))
55
+ sql = "CREATE TABLE %s (%s)" % (table, ",".join(definition))
56
+ return sql
57
+
58
+ @staticmethod
59
+ def __drop_table__(table):
60
+ sql = "DROP TABLE %s" % (table)
61
+ return sql
62
+
63
+ def __update__(self, table, data, where):
64
+ sql = "UPDATE %s SET %s" % (table, self.__set__(data))
65
+ if isinstance(where, dict):
66
+ sql += " WHERE %s" % self.__where__(where)
67
+ return sql
68
+
69
+
70
+ def __select__(self, table, fields, where=None, orderby=None):
71
+ sql = "SELECT %s FROM %s" % (",".join(fields), table)
72
+ if isinstance(where, dict):
73
+ sql += " WHERE %s" % self.__where__(where)
74
+ if isinstance(orderby, str):
75
+ sql += " ORDER BY %s" % (orderby)
76
+ return sql
77
+
78
+ def __delete__(self, table, where):
79
+ sql = "DELETE FROM %s WHERE %s" % (table, self.__where__(where))
80
+ return sql
81
+
82
+ class Model(QueryBuilder):
83
+
84
+ def __init__(self, conn, table, schema):
85
+ self.conn = conn
86
+ self.table = table
87
+ self.schema = schema
88
+
89
+ def down(self):
90
+ sql = self.__drop_table__(self.table)
91
+ cur = self.conn.cursor()
92
+ cur.execute(sql)
93
+ self.conn.commit()
94
+ return cur.rowcount
95
+
96
+ def up(self):
97
+ sql = self.__create_table__(self.table, self.schema)
98
+ cur = self.conn.cursor()
99
+ cur.execute(sql)
100
+ self.conn.commit()
101
+ return cur.rowcount
102
+
103
+ def insert(self, data):
104
+ sql = self.__insert__(self.table, data)
105
+ cur = self.conn.cursor()
106
+ cur.execute(sql)
107
+ self.conn.commit()
108
+ return cur.lastrowid
109
+
110
+ def update(self, where, data):
111
+ sql = self.__update__(self.table, data, where)
112
+ cur = self.conn.cursor()
113
+ cur.execute(sql)
114
+ self.conn.commit()
115
+ return cur.rowcount
116
+
117
+ def delete(self, where):
118
+ sql = self.__delete__(self.table, where)
119
+ cur = self.conn.cursor()
120
+ cur.execute(sql)
121
+ self.conn.commit()
122
+ return cur.rowcount
123
+
124
+ def find(self, where=None):
125
+ sql = self.__select__(self.table, ["*"], where)
126
+ cur = self.conn.cursor()
127
+ cur.execute(sql)
128
+ rows = cur.fetchall()
129
+ return rows
130
+
131
+ def first(self, where):
132
+ sql = self.__select__(self.table, ["*"], where)
133
+ cur = self.conn.cursor()
134
+ cur.execute(sql)
135
+ row = cur.fetchone()
136
+ return row
137
+
138
+ class ORM:
139
+
140
+ __models__ = {}
141
+ __instance__ = None
142
+
143
+ @staticmethod
144
+ def instance(filename, password, salt, schema):
145
+ if ORM.__instance__ == None:
146
+ ORM.__instance__ = ORM(filename, password, salt, schema)
147
+ return ORM.__instance__
148
+
149
+ def __init__(self, filename, password, salt, schema):
150
+
151
+ self.filename = filename
152
+ self.password = password
153
+ self.salt = salt
154
+ self.__instance__ = self
155
+
156
+ install = False
157
+ if os.path.exists(filename) == False:
158
+ install = True
159
+
160
+ self.conn = open_cdb(self.filename, self.password, self.salt)
161
+
162
+ for table in schema:
163
+ self.__models__[table] = Model(self.conn, table, schema[table])
164
+ if install:
165
+ self.__models__[table].up()
166
+ if install:
167
+ save_cdb(self.conn, self.filename, self.password, self.salt)
168
+
169
+ def model(self, name) -> Model|None:
170
+ if name in self.__models__:
171
+ return self.__models__[name]
172
+ return None
173
+
174
+ def save(self):
175
+ save_cdb(self.conn, self.filename, self.password, self.salt)