]> git.datanom.net - securemail.git/blame - db.py
Make backwards compatible with nacl 1.0.x
[securemail.git] / db.py
CommitLineData
8c4f590c
MR
1# -*- coding: utf-8 -*-
2
3# Copyright (c) 2018 Michael Rasmussen <mir@datanom.net>
4
5# This file is part of SecureMail.
6
7# SecureMail is free software: you can redistribute it and/or modify
8# it under the terms of the GNU General Public License as published by
9# the Free Software Foundation, either version 3 of the License, or
10# (at your option) any later version.
11#
12# SecureMail is distributed in the hope that it will be useful,
13# but WITHOUT ANY WARRANTY; without even the implied warranty of
14# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15# GNU General Public License for more details.
16#
17# You should have received a copy of the GNU General Public License
18# along with SecureMail. If not, see <https://www.gnu.org/licenses/>.
19
7084ca4a 20# sqlite
6004ded9
MR
21sqlite_sql = """create table account (
22id int auto_increment,
23token char(128) unique not null,
24cipher text not null,
25primary key (id))"""
26
d65fab5a 27# mysql
6004ded9
MR
28mysql_sql = """create table account (
29id int auto_increment,
30token char(128) unique not null,
31cipher text not null,
32primary key (id))"""
33
d65fab5a 34# postgresql
6004ded9
MR
35postgresql_sql = """create table account (
36id serial,
37token char(128) unique not null,
38cipher bytea not null,
39primary key (id))"""
d65fab5a
MR
40
41import base64
7084ca4a
MR
42from config import DBTYPE, DBNAME
43try:
44 from config import DBUID
45except ImportError:
46 DBUID = 'backend'
47try:
48 from config import DBPWD
49except ImportError:
50 DBPWD = 'clV77B2ZJQxr'
51try:
52 from config import DBHOST
53except ImportError:
54 DBHOST = 'localhost'
55try:
56 from config import DBPORT
57except ImportError:
58 if DBTYPE == 'mysql':
59 DBPORT = 3306
60 elif DBTYPE == 'postgresql':
61 DBPORT = 5432
d65fab5a 62from cryptonize import Cryptonize
8c4f590c
MR
63
64class Singleton:
65 def __init__(self, klass):
66 self.klass = klass
67 self.instance = None
68
69 def __call__(self, *args, **kwargs):
70 if self.instance == None:
71 self.instance = self.klass(*args, **kwargs)
72 return self.instance
73
74@Singleton
75class DB:
76 conn = None
77
78 def get_connection(self):
79 if self.conn is None:
80 if DBTYPE == 'mysql':
d65fab5a 81 import MySQLdb
d5c0fb7f 82 self.conn = MySQLdb.connect(host=DBHOST, port=DBPORT, user=DBUID, passwd=DBPWD, db=DBNAME)
8c4f590c
MR
83 elif DBTYPE == 'postgresql':
84 import psycopg2
85 self.conn = psycopg2.connect(host=DBHOST, port=DBPORT, user=DBUID, password=DBPWD, dbname=DBNAME)
7084ca4a
MR
86 elif DBTYPE == 'sqlite':
87 import apsw
88 self.conn = apsw.Connection('./{0}.db'.format(DBNAME))
d65fab5a
MR
89 else:
90 raise ValueError('{0}: Unsupported database'.format(DBTYPE))
8c4f590c
MR
91 return self.conn
92
93 def __del__(self):
94 if self.conn is not None:
95 self.conn.close()
96
97class DBInterface:
98 @staticmethod
99 def load_user(key):
100 conn = DB().get_connection()
101 cursor = conn.cursor()
d65fab5a 102 cursor.execute("select a.cipher from account a where token = '{0}'".format(key))
8c4f590c
MR
103 row = cursor.fetchone()
104 if row is None:
105 obj = None
106 else:
d65fab5a
MR
107 c = Cryptonize()
108 msg = base64.b64decode(row[0])
109 obj = c.create_EncryptedMessage(msg)
8c4f590c
MR
110 cursor.close()
111
112 return obj
113
114 @staticmethod
115 def store_user(key, cipher):
d65fab5a
MR
116 if DBTYPE == 'mysql':
117 from MySQLdb import Error as DBError
118 elif DBTYPE == 'postgresql':
119 from psycopg2 import Error as DBError
7084ca4a
MR
120 elif DBTYPE == 'sqlite':
121 from apsw import Error as DBError
8c4f590c
MR
122 conn = DB().get_connection()
123 cursor = conn.cursor()
d65fab5a
MR
124 raw = base64.b64encode(cipher)
125 try:
7084ca4a
MR
126 if DBTYPE != 'sqlite':
127 cursor.execute("insert into account(token, cipher) values(%s, %s)", (key, raw))
128 conn.commit()
129 else:
130 cursor.execute('begin')
131 cursor.execute("insert into account(token, cipher) values(?, ?)", (key, raw))
132 cursor.execute('commit')
d65fab5a
MR
133 except DBError as e:
134 print (e)
7084ca4a
MR
135 if DBTYPE != 'sqlite':
136 conn.rollback()
137 else:
138 cursor.execute('rollback')
d65fab5a
MR
139 raise e
140 finally:
141 cursor.close()
6004ded9
MR
142
143 @staticmethod
144 def create_database():
145 if DBTYPE == 'mysql':
146 from MySQLdb import Error as DBError
147 elif DBTYPE == 'postgresql':
148 from psycopg2 import Error as DBError
149 elif DBTYPE == 'sqlite':
150 from apsw import Error as DBError
151 conn = DB().get_connection()
152 cursor = conn.cursor()
153 try:
154 if DBTYPE != 'sqlite':
155 if DBTYPE == 'mysql':
156 sql = mysql_sql
157 elif DBTYPE == 'postgresql':
158 sql = postgresql_sql
159 cursor.execute(sql)
160 conn.commit()
161 else:
162 cursor.execute('begin')
163 cursor.execute(sqlite_sql)
164 cursor.execute('commit')
165 except DBError as e:
6004ded9
MR
166 if DBTYPE != 'sqlite':
167 conn.rollback()
168 else:
169 cursor.execute('rollback')
170 raise e
171 finally:
172 cursor.close()
173
174def main():
175 from optparse import OptionParser
176
177 usage = "usage: %prog [options] arg"
178 parser = OptionParser(usage)
179 parser.add_option("-c", "--create", action="store_true", dest="create",
180 help="Create tables in database using config.py", default=False)
181 parser.add_option("-v", "--verbose", action="store_true", dest="verbose",
182 help="Run in verbose mode", default=False)
183 (options, args) = parser.parse_args()
184
185 if options.create:
186 try:
187 if options.verbose:
188 print("Creating empty database")
189 print("Database Engine: {0}".format(DBTYPE))
190 if DBTYPE != 'sqlite':
191 print("Database Host: {0}".format(DBHOST))
192 print("Database Port: {0}".format(DBPORT))
193 else:
194 print("Database File: ./{0}.db".format(DBNAME))
195 DBInterface.create_database()
196 print("Database created")
197 except Exception as e:
198 print("Creating database failed!")
199 print(e)
200
201if __name__ == '__main__':
202 main()
This page took 0.087769 seconds and 5 git commands to generate.