基于python的安全即时通讯系统
資源下載地址:https://download.csdn.net/download/sheziqiong/85596120
資源下載地址:https://download.csdn.net/download/sheziqiong/85596120
Uchat——基于 python 的安全即時通訊系統(tǒng)
目的
設(shè)計完成簡易的安全即時通訊系統(tǒng),實現(xiàn)類似于 QQ 的聊天軟件;
需求分析
功能需求
聊天客戶端
功能結(jié)構(gòu)圖
集中服務(wù)器
功能結(jié)構(gòu)圖
高級功能
數(shù)據(jù)需求
客戶端
客戶端登錄后加過的好友和加入的群聊需要從數(shù)據(jù)庫中調(diào)出信息并在前端反饋呈現(xiàn)出來。客戶端的聊天記錄可以存儲在數(shù)據(jù)庫中,用到時直接讀取返回消息歷史。
集中服務(wù)器
users 表:用戶信息表,存儲用戶基本信息,包括用戶 ID(id)、用戶名(username)、密碼(password)、電子郵箱(email)、用戶登錄 IP 地址(ip)、用戶登錄端口(port)、性別(sex)、年齡(age)、公鑰(pk)。
| id | INTEGER | Y | Y | N | 用戶 id |
| username | TEXT | N | Y | N | 用戶名 |
| password | TEXT | N | Y | N | 密碼 |
| TEXT | N | Y | N | 郵箱 | |
| ip | TEXT | N | Y | N | 登錄 IP |
| port | TEXT | N | Y | N | 登錄端口 |
| sex | TEXT | N | Y | N | 性別 |
| age | TEXT | N | Y | N | 姓名 |
| pk | TEXT | N | Y | N | 公鑰 |
friends 表:存儲用戶的好友信息,包括用戶 id(from_user_id)、好友 id(to_user_id)、加好友請求是否接受(accepted)。
| from_user_id | INTEGER | Y | Y | N | 本人 ID |
| to_user_id | INTEGER | Y | Y | N | 好友 ID |
| accept | BOOLEAN | N | N | N | 接受狀態(tài) |
chat_history 表:存儲好友的聊天記錄,包括發(fā)送方 ID(user_id)、接收方(target_id)ID(target_type)、聊天數(shù)據(jù)(data)(BLOB 類型存儲二進制大對象,可以實現(xiàn)文件數(shù)據(jù)的直接存儲),sent(用于標識消息是否已發(fā)送,若未發(fā)送,先存儲這個操作,在某一次事件再次觸發(fā)時檢查標志位,操作服務(wù)端再次控制 client.socket 發(fā)送消息)。
| id | INTEGER | Y | Y | N | 消息 ID |
| user_id | INTEGER | N | N | N | 用戶 ID |
| target_id | INTEGER | N | N | N | 消息目標 ID |
| target_type | TEXT | N | N | N | 目標類型:群/用戶 |
| data | BLOB | N | N | N | 消息體 |
| sent | BOOLEAN | N | N | N | 發(fā)送是否成功 |
rooms 表:群組表,包括該群組的主鍵 ID(id)、群組的名稱(room_name)。
| id | INTEGER | Y | Y | N | 群聊 ID |
| room_name | TEXT | N | Y | N | 群聊名 |
room_user 表:群組用戶表,包括群組的 ID,群聊房間號(room_id)、加入該群組的用戶(user_id)。
| id | INTEGER | Y | Y | N | ID |
| room_id | INTEGER | N | N | N | 群聊 ID |
| user_id | INTEGER | N | N | N | 用戶 ID |
性能需求
可靠性需求
保證一個用戶只能同時使用一個 IP 地址登錄,客戶端不會出現(xiàn)閃退、加密無效的情況。
安全性需求
客戶端做好完整的封裝;傳輸信息采用經(jīng)過公鑰加密機制協(xié)商的 AES 對稱加密秘鑰;服務(wù)器及時更新客戶端 IP 地址等信息。
可維護性與可擴展性需求
對于軟件功能方面,采用高內(nèi)聚低耦合的模塊化設(shè)計,包括登錄模塊、注冊模塊、好友列表模塊、聊天模塊等,確保每個模塊的具有較高的獨立性,使軟件源碼便于維護,同時便于后期添加聊天群等更多擴展內(nèi)容,保證軟件可以進行更新?lián)Q代。
運行環(huán)境需求
客戶端:python3
服務(wù)端:
python3
PC 硬盤容量:50G
運行內(nèi)存:2G
UI 需求
操作需求
詳細設(shè)計
系統(tǒng)結(jié)構(gòu)說明
本系統(tǒng)的核心控制邏輯在于 C-S-C 之間發(fā)送的數(shù)據(jù)中包含了操作碼,接收方通過對接收碼的識別作出規(guī)定的操作。例如服務(wù)端接收添加好友的操作碼會執(zhí)行 add_friend.py。客戶端接收操作碼并不斷把對應(yīng)函數(shù)放入遞歸函數(shù)的隊列中,由遞歸函數(shù)逐一執(zhí)行隊列中的函數(shù)。
系統(tǒng)主要分為三個部分:
- 聊天客戶端(client)
- 集中服務(wù)器(server)
- 相互通信時的共同部分(common)
聊天客戶端 client
實現(xiàn)安全即時通信系統(tǒng)的客戶端,主要功能是通過界面與用戶實現(xiàn)交互;通過 socket 與集中服務(wù)器進行通信,獲得集中服務(wù)器的服務(wù),實現(xiàn)用戶的注冊登錄等功能。與好友即時通信和加入群聊通信。
該模塊創(chuàng)建登錄界面并可鏈接到注冊界面,若輸入為空則報錯,否則將獲取用戶輸入的用戶名和密碼打包成登錄請求消息(MessageType.login)發(fā)送給服務(wù)器,服務(wù)器根據(jù)消息類型和數(shù)據(jù)包中的內(nèi)容以及在數(shù)據(jù)庫查找到的結(jié)果進行判斷,根據(jù)不同情況發(fā)送不同的反饋給客戶端。客戶端收到反饋消息,若 data[‘type’]為 login_failed,則用戶名和密碼輸入有誤;若為 data[‘type’]為 login_successful 則根據(jù) memory 進入登錄后顯示好友列表的 ContractsForm 界面。
該模塊只有在登錄界面點擊注冊按鈕時才會顯示。通過注冊窗口獲得用戶輸出的個人信息:用戶名、密碼、郵箱、性別、年齡,若其中用戶名、郵箱、密碼為空或兩次密碼輸入不一致則會提示相應(yīng)的錯誤以引導(dǎo)用戶進行正確的輸入,否則將獲取用戶輸入打包成注冊請求消息(MessageType.register)發(fā)送給服務(wù)器。服務(wù)器查找數(shù)據(jù)庫判斷是否用戶名已經(jīng)注冊過,發(fā)送不同反饋給用戶,若 data[‘type’]為 username_taken,則用戶名已被注冊,若 data[‘type’]為 MessageType.register_successful 則注冊成功,并且在客戶端生成證書包含用戶的用戶名,郵箱,公鑰。
該模塊在用戶登錄成功以后顯示。顯示好友列表中好友的用戶名、在線狀態(tài),ip 地址及端口號等。下方的按鈕有添加好友、刪除好友、添加群聊、創(chuàng)建群聊。可以點擊相應(yīng)的按鈕進行相應(yīng)的操作,發(fā)給服務(wù)器相應(yīng)的數(shù)據(jù)包,服務(wù)器接收到數(shù)據(jù)包后進行解析,根據(jù)不同類型進行 event_handler。若點擊好友列表或群聊即可跳出聊天界面進行聊天。未讀的消息會用紅點標注,根據(jù)最后一條消息的發(fā)送時間來對好友列表排序。
該模塊是用戶與好友聊天的界面。當用戶在好友列表中點擊好友列表時,即向好友發(fā)出聊天,服務(wù)器收到聊天請求后尋找對方的證書,找到對方的公鑰,雙方使用 Diffie-Hellman 算法協(xié)商算法,然后利用 AES 加密消息保證消息的機密性,MD5 生成消息摘要驗證保證消息的完整性。另外還可以更改聊天過程中字體的大小和顏色,支持多行輸入,支持發(fā)送文件,以圖片為例,將保存聊天過程中的接收到的圖片,并識別其格式。
該模塊實現(xiàn) tkinter 靜態(tài)部件添加和滾動模塊的實現(xiàn)。
該模塊用于初始化 tkinter 對象 tk 的屬性,如窗口,secure_channel 對象等。
該模塊用于客戶端處理消息類型,文本或其他。以及不斷循環(huán)建立連接 socket 接收消息,實現(xiàn)數(shù)據(jù)包的完整接收。定義處理給好友框,消息框更新歷史消息的函數(shù),事件操作的監(jiān)聽函數(shù)和移除函數(shù),消息的監(jiān)聽函數(shù)和移除函數(shù)。可以實現(xiàn)接收數(shù)據(jù)并且拼成塊,更新聊天的歷史記錄,通知客戶端更新 contacts 界面上的最后一條消息的內(nèi)容,時間,未讀消息的數(shù)目等。
集中服務(wù)器 server
該模塊分為 11 個部分,分別具體處理客戶端發(fā)來的各個操作事件。如登錄加好友刪除好友等操作。
該模塊主要是根據(jù)客戶端觸發(fā)的事件對數(shù)據(jù)庫的各種操作。
該模塊主要是針對群聊,為群組中的每個在線用戶廣播發(fā)送消息。
定義用戶與 secure_channel 對象互相映射的字典列表,所有已經(jīng)建立的 secure_channel 對象,以及用戶下線后將其從在線 secure_channel 對象列表中移除的操作。
客戶端服務(wù)器公用模塊 common
將變量數(shù)據(jù)等變成可存儲或者傳輸?shù)倪^程即序列化,同時還將各個事件的類型變?yōu)槊杜e變量保存,將收到的數(shù)據(jù)包反序列化進行恢復(fù),再提取數(shù)據(jù)包中 Message 的類型。
用于調(diào)用其生成公鑰,然后從證書中獲取公鑰,再使用 D-H 算法協(xié)商生成共享密鑰。
該模塊主要是判斷是否為素數(shù),生成大素數(shù),為證書的生成提供基礎(chǔ)。
該模塊主要是定義 secure_channel 類,即包裹了 socket 和參數(shù)秘鑰的封裝對象。在通信對象之間協(xié)商好對稱加密秘鑰之后封裝在這個新的對象中。并且這個對象對數(shù)據(jù)有新的函數(shù)功能:
- send 函數(shù)
用于對發(fā)送的序列化之后的數(shù)據(jù)用對稱加密秘鑰進行 AES 加密并用 struct 結(jié)構(gòu)體將其打包成自設(shè)協(xié)議格式的數(shù)據(jù)包。 - on_data
函數(shù)主要用于接受數(shù)據(jù)的逆向解析。按照要求配置 socket 和數(shù)據(jù)傳輸?shù)母袷竭M行規(guī)則化。數(shù)據(jù)包的格式為前四個字節(jié)為消息體的長度,接著一字節(jié)存儲 AES 加密時的消息填充長度,然后 16 字節(jié) AES 加密時所需要的初始值,再接著是 32 字節(jié)的消息摘要,最后才是加密后的消息體。
重要數(shù)據(jù)說明
發(fā)送接收的數(shù)據(jù)格式
接收數(shù)據(jù)時的三個字典
全局都在引用的數(shù)據(jù)
客戶端接收到的數(shù)據(jù) data
data 是一部字典,它包括 key:parameters,type.parameters 也是一部字典,內(nèi)部包括 key:target_type,time,sender_id(發(fā)送者 id),target_id(接收方 id),sender_name(接收者姓名,message 字典(內(nèi)含數(shù)據(jù)內(nèi)容,字體,字體大小顏色)。而外層的這個 type 存儲的是交給 server 的 MessageType 類型,如果是不同的 MessageType 會進行不同的數(shù)據(jù)庫操作和客戶端操作。具體實例如下:
data={'parameters':{ 'target_type':0, 'time':1562754761321, 'sender_id':1, 'target_id':2, 'sender_name':'1', 'message'{ 'data':'hello', 'fontsize':10, 'type':0, 'fontcolor':'#000000' } },'type':<MessageType.on_new_message:109> }例子中 data[‘parameters’][‘target_type’]=0 表示文本信息,從 id 為 1 的用戶發(fā)出信息,發(fā)給 id 標號為 2 的人,發(fā)送方昵稱為‘1’。給服務(wù)器發(fā)送的操作碼為 109。
安全傳輸
數(shù)據(jù)包結(jié)構(gòu)
消息加密算法:AES 對稱加密算法,保證消息機密性
消息摘要算法:MD5 算法,保證消息的完整性
包結(jié)構(gòu)分析
第一層(解密前)
通過函數(shù) struct.pack()構(gòu)造加密的數(shù)據(jù)包,結(jié)構(gòu)如下
相關(guān)代碼如下
iv1=bytes(os.urandom(16))data_to_encrypt=serialize_message(message_type,parameters) length_of_message=len(data_to_encrypt) padding_n=math.ceil(length_of_message/16)*16-length_of_messageforiinrange(0,padding_n):data_to_encrypt+=b'\0'其中 iv1 是 16 字節(jié)隨機數(shù)作為初始向量。要加密的數(shù)據(jù)是序列化的初始數(shù)據(jù)。獲取長度后用\0 填充。然后將數(shù)據(jù)用 python 庫函數(shù) aes,cbc 模式加密得到加密數(shù)據(jù)。
第二層(解密后)
結(jié)構(gòu)如下
-
MessageType:event_handler_map()規(guī)定的操作碼
-
Parameter:字典參數(shù),包含 target_type(標志群聊或者私聊)等
第三層,序列化數(shù)據(jù)的安排格式
第四層,基礎(chǔ)數(shù)據(jù)部分
包括 int、str、bool、float、binary 等
密鑰分發(fā)
協(xié)商過程
客戶端的證書、公鑰、私鑰
加密算法
采用 DH 協(xié)商對稱加密的共享密鑰,具體過程如下
程序函數(shù)清單
客戶端函數(shù)
socket_listener(self,data)
-
位置
- client/forms/register_form.py
- client/forms/login_form.py
- client/forms/contacts_form.py
- client/forms/chat_form.py
-
參數(shù)
- self:所在的類的自身
- data:監(jiān)聽數(shù)據(jù)
-
功能
在注冊、登錄、好友列表、聊天框四個頁面建立事件監(jiān)聽,解析監(jiān)聽 data,確定數(shù)據(jù)中 MessageType 的類型,在 register_form.py 文件中用于判斷用戶名是否被占用、返回注冊結(jié)果;在 login_form.py 中用于返回登錄結(jié)果;在 contacts_form.py 文件中用于判斷是否處理添加、刪除好友、添加、創(chuàng)建群聊以及執(zhí)行操作的結(jié)果、判斷好友是否下線并刷新好友列表。
remove_socket_listener_and_close(self)
-
位置
- client/forms/register_form.py
- client/forms/login_form.py
- client/forms/contacts_form.py
- client/forms/chat_form.py
-
參數(shù)
- self:所在的類的自身:RegisterForm、LoginForm、ContactsForm、ChatForm
-
功能
通過調(diào)用 util/socket_listener 文件下的 remove_listener 函數(shù)來關(guān)閉事件監(jiān)聽,同時調(diào)用庫函數(shù) destroy()關(guān)閉窗口、清空客戶端緩存信息。
_init_(self,master=None)
-
位置
- client/forms/register_form.py
-
參數(shù)
- self:所在類 RegisterForm 自身
- master:注冊主窗口用來容納其他組件,默認一個窗口 master=None
-
功能
通過庫函數(shù) super()實現(xiàn)子類__init__()對父類__init__()的繼承;對注冊窗口進行布局,包括確定注冊界面的長寬,確定背景、標簽、輸入框、按鈕等的位置、顏色、類型、鏈接等;初始化安全信道;通過 socket_listener()函數(shù)和 remove_socket_listener_and_close()函數(shù)控制對客戶端 socket 事件監(jiān)聽和關(guān)閉。
do_register(self)
-
位置
- client/forms/register_form.py
-
參數(shù)
- self:所在類 RegisterForm 自身
-
功能
檢查輸入的用戶名、密碼、郵箱是否合法;判斷兩次輸入的密碼是否相同;調(diào)用 get_ip()函數(shù)獲取客戶端的 IP 地址和端口號;向服務(wù)器發(fā)送注冊請求,并通過調(diào)用函數(shù) send()將注冊輸入的用戶名、密碼、郵箱、性別、年齡以及用戶的 IP 地址和端口號等信息發(fā)送給服務(wù)器;構(gòu)造數(shù)字證書,命名為 IP 地址 +“——cert.pem”,內(nèi)容為用戶名 + 郵箱 + 用戶公鑰
._init_(self,master=None)
-
位置
- client/forms/login_form.py
-
參數(shù)
- self:所在類 RegisterForm 自身
- master:登錄主窗口用來容納其他組件,默認一個窗口 master=None
-
功能
通過庫函數(shù) super()實現(xiàn)子類__init__()對父類_init_()的繼承;對登錄窗口進行布局,包括確定注冊界面的長寬,確定背景、標簽、輸入框、按鈕等的位置、顏色、類型、鏈接等;初始化安全信道;通過 socket_listener()函數(shù)和 add_listener()函數(shù)將服務(wù)器端加入到監(jiān)聽列表中。
do_login(self)
-
位置
- client/forms/login_form.py
-
參數(shù)
- 參數(shù) self:所在類 LoginForm 自身
-
功能
檢查輸入的用戶名、密碼是否合法;通過調(diào)用函數(shù) send()向服務(wù)器發(fā)送登錄請求,并將輸入的用戶名、密碼等信息發(fā)送給服務(wù)器。
show_register(self)
-
位置
- client/forms/login_form.py
-
參數(shù)
- self:所在類 LoginForm 自身
-
功能
與注冊按鈕關(guān)聯(lián),通過點擊按鈕調(diào)用庫函數(shù) Toplevel()跳轉(zhuǎn)到注冊頁面。
._init_(self,master=None)
-
位置
- client/forms/contacts_form.py
-
參數(shù)
- self:所在類 ContactsForm 自身
- master:登錄主窗口用來容納其他組件,默認一個窗口 master=None。
-
功能
通過庫函數(shù) super()實現(xiàn)子類_init__()對父類__init_()的繼承;對好友列表窗口布局,確定好友列表的長寬、按鈕的位置、顏色、類型、鏈接等;調(diào)用 VerticalScrolledFrame()函數(shù),將列表設(shè)置滾動條 + 圖片背景;初始化安全信道;通過 socket_listener()函數(shù)和 remove_socket_listener_and_close()函數(shù)控制對客戶端 socket 事件監(jiān)聽和關(guān)閉。
refresh_contacts(self)
-
位置
- client/forms/contacts_form.py
-
參數(shù)
- self:所在類 ContactsForm 自身
-
功能
通過比較與好友或群聊最近一次發(fā)消息的時間 last_message_timestamp 和好友的在線情況刷新好友列表,根據(jù)好友或群聊發(fā)送消息的時間遠近對好友列表進行排列,并將在線好友移至列表頂部
on_add_friend(self)/on_del_friend(self)/on_add_room(self)on_create_room(self)
-
位置
- client/forms/contacts_form.py
-
參數(shù)
- self:所在類 ContactsForm 自身
-
功能
與添加好友、刪除好友、添加群聊、創(chuàng)建群聊四個按鈕鏈接;使用庫函數(shù) simpledialog.askstring()彈出輸入框,并對輸入的內(nèi)容進行檢驗;使用函數(shù) send()向服務(wù)器發(fā)送操作請求。
handle_new_contact(self,data)
-
位置
- client/forms/contacts_form.py
-
參數(shù)
- self:所在類 ContactsForm 自身
- data:接收的數(shù)據(jù)
-
功能
被該文件下的另一個函數(shù)__init__()調(diào)用用來添加或刪除列表中的好友。
_init_(self,target,master=None)
-
位置
- client/forms/chat_form.py
-
參數(shù)
- self:所在類 ChatFrame 自身
- target:一個用來暫時存儲消息的列表
- master:聊天框主窗口用來容納其他組件,默認一個窗口 master=None
-
功能
對聊天框布局,確定聊天框的長寬、輸入框、消息框、按鈕的位置、顏色、類型、鏈接等;分辨私人聊天和群聊;利用 append_to_chat_box()函數(shù)加載、更新歷史消息。
send_message(self)/send_file(self)
-
位置
- client/forms/chat_form.py
-
參數(shù)
- self:所在類 ChatFrame 自身
-
功能
通過調(diào)用 input_textbox.get()函數(shù)和 filedialog.askopenfilename()函數(shù)實現(xiàn)發(fā)送消息和文件。
digest_message(self,data)
-
位置
- client/forms/chat_form.py
-
參數(shù)
- self:所在類 ChatFrame 自身
- data:傳輸?shù)臄?shù)據(jù)
-
功能
通過分析傳輸?shù)臄?shù)據(jù)包,摘取消息的時間戳、發(fā)送者、消息類型,為布局做準備。
_init_(self,parent,onclick)
-
位置
- client/components/contact_item.py
-
參數(shù)
- self:所在類 ContactItem 自身
- parent:向函數(shù)內(nèi)定義的子類傳遞的參數(shù)
- onclick:跳轉(zhuǎn)動作
-
功能
位于 ContactItem 類中,對好友列表中的每一行進行布局如
_init_(self,parent,*args,**kw)
-
位置
- client/components/vertical_scrolled_frame.py
-
參數(shù)
- self:所在類 VerticalScrolledFrame 自身
- parent:向函數(shù)內(nèi)定義的子類傳遞的參數(shù)
- *args:可變參數(shù)
- **kw:關(guān)鍵字參數(shù)
-
功能
利用 Scrollbar()函數(shù)創(chuàng)建一個帶有滾動條的畫布,并可以通過滾動條對畫布及時更新。
common 函數(shù)
gen_secret()
-
位置
- common\cryptography\crypt.py
-
功能
產(chǎn)生用戶的公鑰私鑰
-
算法描述
利用 prime.generate_big_prime()函數(shù)產(chǎn)生一個大的素數(shù)作為私鑰,然后利用相應(yīng)算法計算出自己的公鑰,將公鑰和私鑰保存成文件,公鑰可寫入證書,私鑰單獨保存不傳輸
_serialize_xxx(xxx)
-
位置
- common\message_init_.py
-
參數(shù):要序列化的數(shù)據(jù)類型
-
功能
針對傳入的不同數(shù)據(jù)類型進行序列化算法描述:對不同數(shù)據(jù)類型進行序列化成二進制然后返回統(tǒng)一格式的數(shù)據(jù),方便進行數(shù)據(jù)的傳輸和存好友的用戶名和在線狀態(tài)最近一次消息時間好友的 IP 地址和端口號消息內(nèi)容未讀消息計數(shù)儲。每個序列化后的數(shù)據(jù)格式為:|——VAR_TYPE(1Byte)——|——DATA_LEN(4Bytes)——|——DATA——|。即 1 字節(jié)數(shù)據(jù)類型,4 字節(jié)數(shù)據(jù)長度和數(shù)據(jù)部分。
主要用_serialize_list(list):_serialize_list(list)數(shù)據(jù)打包格式如下:|——1ByteTypeofparams——|——4BytesLengthofbody——|——Body(self-evidentlength)——|——Body(selfevidentlength)——|——Body(self-evidentlength)——|…即第一字節(jié)為列表類型,然后 4 字節(jié)的數(shù)據(jù)長度,由每種數(shù)據(jù)類型占用長度不同分配不同的 BODY 長度,每一個 BODY 可以是如 list,int,float 等數(shù)據(jù)類型。
_deserialize_xxx(bytes)
-
位置
- common\message_init_.py
-
參數(shù):二進制數(shù)據(jù)
-
功能
針對傳入的不同數(shù)據(jù)類型數(shù)據(jù)進行反序列化成原本數(shù)據(jù)
-
算法描述
對二進制進行反序列成指定的數(shù)據(jù)類型,即是_serialize_xxx 的逆過程,可用于解析數(shù)據(jù)包。
send(self,message_type,parameters=None)
-
位置
- common\transmission\secure_channel.py
-
參數(shù)
- self 即為 SecureChannel 類
- message_type 即為消息的類型
-
功能
按照自制的協(xié)議組織數(shù)據(jù)包發(fā)送數(shù)據(jù)包
-
算法描述
數(shù)據(jù)包的格式為前四個字節(jié)為消息體的長度,接著一字節(jié)存儲 AES 加密時的消息填充長度,然后 16 字節(jié) AES 加密時所需要的初始值,再接著是 32 字節(jié)的消息摘要,最后才是加密后的消息體。
on_data(self,data_array)
-
位置
- common\transmission\secure_channel.py
-
參數(shù)
- self 即為 SecureChannel 類
- data_array 即為字節(jié)數(shù)組
-
功能
解析數(shù)據(jù)包,并利用 mac 驗證消息的完整性
-
算法描述
首先把 bytes([padding_n])+iv1+encrypted_message 傳給本函數(shù),然后得到消息體,和消息摘要,接收方對消息利用相同的算法計算其消息摘要,驗證消息是否被篡改最后對消息解密,返回解密后的反序列化后的原始數(shù)據(jù)。
establish_secure_channel_to_server()
-
位置
- common\transmission\secure_channel.py
-
功能
與集中服務(wù)器建立安全信道
-
算法描述
客戶端首先獲取本機的 ip 地址,生成自己的私鑰公鑰和證書,首次連接的時候要給服務(wù)器發(fā)送證書,計算出二者的共同密鑰。
accept_client_to_secure_channel(socket)
-
位置
- common\transmission\secure_channel.py
-
參數(shù)
- socket:客戶端和服務(wù)器通信的 socket
-
功能
服務(wù)器接收客戶端建立安全信道
-
算法描述
首次連接,客戶端會發(fā)送公鑰,把服務(wù)器的證書發(fā)送給客戶端,二者計算出共同密鑰。
gen_last_message(obj)
-
位置
- common\utli\socket_listener\__init__.py
-
參數(shù)
- obj 為傳輸數(shù)據(jù) data 的 obj 類型
-
功能
獲取對象中 message 的類型,0 表示文字信息,1 表示圖片信息
-
算法描述
obj[‘message’][‘type’]判斷 0 與 1.type0-文字消息 1-圖片消息。
socket_listener_thread(sc,tk_root)
-
位置
- common\socket_listener__init.py
-
參數(shù)
- sc 是已經(jīng)建立的 C-S 安全 socket,socket_channel,帶有對稱秘鑰
- tk_root 是 tkinter 界面對象。
-
功能
循環(huán)接收信息,進入 socket 監(jiān)聽狀態(tài),當接受到信息后完整的接收數(shù)據(jù)包并從中獲取操作碼,根據(jù)操作碼的不同進行不同的處理。
-
算法描述
使用 select.select 函數(shù)阻塞運行,當有處理時不會被其他人占用。其中接受數(shù)據(jù)有三個變量:
- bytes_to_receive=0
- bytes_received=0
- data_buffer=bytes()
當 bytes_to_receive=0、bytes_received=0 時表示正準備接受一個新的 socket 數(shù)據(jù)。開始接收后會通過數(shù)據(jù)包前四個字節(jié)判斷長度。如果長度小于四字節(jié)說明是損壞的包或者是空包,沒有數(shù)據(jù),表示服務(wù)器已關(guān)閉。通過指針[0]+1+16 使指針指向數(shù)據(jù)部分。+1 是 aes 的填充部分 1 字節(jié),+16 是 aes 初始向量 4 字節(jié)。直到接收完畢為止。接受完會把數(shù)據(jù)包解包取出數(shù)據(jù)部分,并不斷拼接形成完整數(shù)據(jù)字符串。
digest_message(data,update_unread_count=True)
-
位置
- common\socket_listene\__init__.py
-
參數(shù)
- data 是要放入的歷史數(shù)據(jù)
- update_unread_count 初始參數(shù)設(shè)置為 True 使消息未讀數(shù)自增
-
功能
實現(xiàn)將歷史數(shù)據(jù)放入 chat_history 列表中,更新最新消息,消息時間,消息未讀數(shù)量,并更新用戶的好友列表,在前端進行刷新,更新聊天窗口。
-
算法描述
通過 if 像 chat_history 中的數(shù)據(jù)填入以前的數(shù)據(jù)。將 data 更新用于發(fā)送。
add_listener(func)
-
位置
- common\socket_listener\__init__.py
-
參數(shù)
- func 是一個函數(shù)
-
功能
將某一函數(shù)事件放入執(zhí)行列表中,之后會被逐個調(diào)用
-
算法描述
將 func 函數(shù) append 到 callback_funcs 待執(zhí)行函數(shù)列表中。
remove_listener(func)
-
位置
- common\socket_listener__init__.py
-
參數(shù)
- func 是一個函數(shù)
-
功能
將某一函數(shù)事件從執(zhí)行列表中移除
-
算法描述
列表的 remove 操作
服務(wù)器端函數(shù)
handler_event
-
位置
- server\event_handler_init_.py
-
參數(shù)
- sc:即為相應(yīng)的 socket;
- event_type:即為事件的類型;
- parameters:相應(yīng)事件中包含的參數(shù)。
-
功能
將不同類型的 event 映射到相應(yīng)的事件處理操作上,比如將 MessageType.login 映射到執(zhí)行 login 的處理操作上。
-
算法描述
主要是利用 map 根據(jù)提供的函數(shù)對指定事件做映射。
run
-
位置
- server\event_handler\login.py
-
參數(shù)
- sc:相應(yīng)的 socket
- parameters:從客戶端傳入的相關(guān)參數(shù)
-
功能
客戶端點擊登錄按鈕后,集中服務(wù)器進行用戶登錄后的相關(guān)操作。
-
算法描述
首先從傳入的參數(shù)中得到用戶的 username 和對應(yīng)的 password,繼而得到對數(shù)據(jù)庫的控制操作權(quán)限,查詢該用戶是否存在,用戶名和密碼是否匹配。若返回值為 0,則為客戶端發(fā)送 MessageType.login_failed。下一步查看該用戶是否已經(jīng)登入,若已登入則踢下線,否則登錄成功,向客戶端發(fā)送 MessageType.login_successful。登錄成功后向客戶端發(fā)送好友列表,通知他的好友他已上線,最后從數(shù)據(jù)庫中讀出他的聊天記錄,將其和好友列表一起作為 login_bundle 的參數(shù)發(fā)送給客戶端。
run
-
位置
- server\event_handler\register.py
-
參數(shù)
- sc:相應(yīng)的 socket;
- parameters:從客戶端傳入的相關(guān)參數(shù)
-
功能
客戶端點擊注冊按鈕后,集中服務(wù)器進行用戶注冊后的相關(guān)操作
-
算法描述
首先從傳入的參數(shù)中獲取用戶名,繼而得到對數(shù)據(jù)庫的控制操作權(quán)限,查詢該用戶名是否已被注冊,若被注冊則向客戶端發(fā)送 MessageType.username_taken,否則的話傳入的參數(shù)中獲取用戶的 ip,重寫用戶生成的證書,然后再把用戶的信息插入到數(shù)據(jù)庫中。
run
-
位置
- server\event_handler\add_friend.py
-
參數(shù)
- sc:相應(yīng)的 socket;
- parameters:從客戶端傳入的相關(guān)參數(shù)
-
功能
客戶端點擊添加好友輸入好友用戶名后,集中服務(wù)器進行用戶添加好友后的相關(guān)操作
-
算法描述
首先從傳入的參數(shù)中得到用戶的 username,繼而得到對數(shù)據(jù)庫的控制操作權(quán)限,查詢該用戶是否存在,若不存在向客戶端發(fā)送 MessageType.add_friend_result,并提示用戶“用戶名不存在”,否則根據(jù)用戶名找到用戶 id,判斷其是否為自己的 id,則提示用戶”不能加自己為好友“。再下一步查詢用戶自己的 id 和好友 id 是否已在 friends 表中,若存在,則提示用戶“已經(jīng)是好友/已經(jīng)發(fā)送過好友請求”,否則的話將用戶自己的 id 和好友 id 插入到 friends 表中,但是 accpted 的值為 0,因為此時還不清楚對方是否同意添加你為好友。然后向用戶發(fā)送 MessageType.add_friend_result,值為 true。最后若對方在線,則向其發(fā)送 MessageType.incoming_friend_request,讓對方處理添加好友的請求。
run
-
位置
- server\event_handler\resolve_friend_request.py
-
參數(shù)
- sc:相應(yīng)的 socket;
- parameters:從客戶端傳入的相關(guān)參數(shù)
-
功能
當有用戶向目標用戶發(fā)送好友添加請求時,服務(wù)器處理好友請求操作
-
算法描述
首先從傳入的參數(shù)中得到 uid,繼而得到對數(shù)據(jù)庫的控制操作權(quán)限,查詢 friends 表中好友關(guān)系(accepted 狀態(tài)為 0)是否在數(shù)據(jù)庫中已存在,若不存在也不進行相關(guān)操作。若拒絕添加好友,則將數(shù)據(jù)庫中的該條數(shù)據(jù)刪除,若同意加為好友,則更新 friends 表 accepted 為 1,并且在數(shù)據(jù)庫中添加雙向關(guān)系。并給客戶端發(fā)送 MessageType.contact_info,在好友列表中顯示添加成功的好友。若對方在線,也發(fā)送 MessageType.contact_info,在好友列表中顯示添加成功的新好友。
run
-
位置
- server\event_handler\del_friend.py
-
參數(shù)
- sc:相應(yīng)的 socket;
- parameters:從客戶端傳入的相關(guān)參數(shù)
-
功能
客戶端點擊刪除好友,輸入好友用戶名后,集中服務(wù)器進行用戶刪除好友后的相關(guān)操作。
-
算法描述
首先從傳入的參數(shù)中得到用戶的 username,繼而得到對數(shù)據(jù)庫的控制操作權(quán)限,查詢該用戶是否存在,若不存在向客戶端發(fā)送 MessageType.add_friend_result,并提示用戶“用戶名不存在”,否則根據(jù)用戶名找到用戶 id,判斷其是否為自己的 id,則提示用戶”不能刪除自己“。再下一步判斷對方是否是自己的好友,查詢用戶自己的 id 和好友 id 是否已在 friends 表中,若不存在,則提示用戶“該用戶還不是您的好友”,若對方是自己的好友,則在 friends 表中刪除二者的好友關(guān)系,并向客戶端發(fā)送 MessageType.del_info,使刪除的好友在好友列表中消失。若對方在線,也發(fā)送 MessageType.del_info,使自己在對方好友列表中也消失,實現(xiàn)雙向的刪好友功能。
run
-
位置
- server\event_handler\create_room.py
-
參數(shù)
- sc:相應(yīng)的 socket;
- parameters:從客戶端傳入的相關(guān)參數(shù)
-
功能
客戶端點擊創(chuàng)建群組聊天,輸入群組名后,集中服務(wù)器進行創(chuàng)建群組的相關(guān)操作。
-
算法描述
首先獲取 user_id,然后將該群聊加入數(shù)據(jù)庫 rooms 中,并且向客戶端發(fā)送 MessageType.contact_info,使用戶在好友列表中顯示群聊。最后向客戶端發(fā)送 MessageType.general_msg,提示用戶創(chuàng)建群聊成功,并顯示群號。
run
-
位置
- server\event_handler\join_room.py
-
參數(shù)
- sc:相應(yīng)的 socket;
- parameters:從客戶端傳入的相關(guān)參數(shù)
-
功能
客戶端點擊添加群組聊天,輸入群組名后,集中服務(wù)器進行添加群聊的相關(guān)操作。
-
算法描述
首先獲取 user_id,調(diào)用數(shù)據(jù)庫的 in_room 函數(shù)判斷用戶是否已在群中,若已在則提示用戶“已在群里了“,調(diào)用數(shù)據(jù)庫的 get_room 函數(shù)判斷群聊是否存在,若不存在提示用戶”群不存在“,否則調(diào)用 add_to_room 將用戶加入到群聊中,并向客戶端發(fā)送 MessageType.contact_info,使用戶在好友列表中顯示該群聊。
get_user(user_id)
-
位置
- server\util\database\__init__.py
-
參數(shù)
- int 型,表示該用戶的用戶 id
-
功能
獲取數(shù)據(jù)庫中 users 表中 id 值為 user_id 的那一行的所有數(shù)據(jù)。
-
算法描述
執(zhí)行數(shù)據(jù)庫查詢語句返回一行結(jié)果。若無結(jié)果返回空。
get_pending_friend_request(user_id)
-
位置
- server\util\database\__init__.py
-
參數(shù)
- user_Id,int 類型,表示某一個用戶的 id 值。
-
功能
返回一個列表,列表中的內(nèi)容為加 user_id 的用戶的好友們的個人信息。
-
算法描述
從數(shù)據(jù)庫中查詢 friends 表,to_user_id 為 user_id 的行中且為 accepted=1 的獲取 from_user,用 get_user 函數(shù)查詢他們的信息并 append 到列表中。
get_friends(user_id)
-
位置
- server\util\database\__init__.py
-
參數(shù)
- user_Id,int 類型,表示某一個用戶的 id 值。
-
功能
類似 get_pending_friend_request(user_id)函數(shù),只是會返回‘我’加誰為好友且 accept 的用戶信息。
-
算法描述
從數(shù)據(jù)庫中查詢 friends 表,from_user_id 為 user_id 的行中且為 accepted=1 的獲取 to_user,用 get_user 函數(shù)查詢他們的信息并 append 到列表中。
get_room(room_id)
-
位置
- server\util\database\__init__.py
-
參數(shù)
- room_id,int 類型,表示一個 room 的 id 值
-
功能
返回群聊 id 為 room_id 的群聊房間在 rooms 表中的所有信息的字典,包括 id,名字
-
算法描述
從數(shù)據(jù)庫中查詢 room 表,返回對應(yīng) room_id 的 room 的全部信息,壓縮為字典并返回。
get_user_rooms(user_id)
-
位置
- server\util\database\__init__.py
-
參數(shù)
- user_Id,int 類型,表示某一個用戶的 id 值。
-
功能
返回一個字典,列表中內(nèi)容為 user_id 用戶加入的群聊的 room 的全部信息。
-
算法描述
從數(shù)據(jù)庫中查詢 room_user 表,返回對應(yīng) user_id 的 room 的全部信息值,變成字典中并返回。
get_user_rooms_id(user_id)
-
位置
- server\util\database\__init__.py
-
參數(shù)
- user_Id,int 類型,表示某一個用戶的 id 值。
-
功能
返回一個列表,列表中內(nèi)容為 user_id 用戶加入的群聊的 room_id。
-
算法描述
從數(shù)據(jù)庫中查詢 room_user 表,返回對應(yīng) user_id 的 room_id 的全部信息值,append 入列表中并返回。
is_friend_with(from_user_id,to_user_id)
-
位置
- server\util\database\__init__.py
-
參數(shù)
- from_user_id 為好友發(fā)起請求方
- to_user_id 為接收好友請求方
-
功能
返回一個判斷值 1 或者 0.判斷兩者是否為朋友。
-
算法描述
從 friends 表中查詢有無兩者建立關(guān)系的一行,若沒有,則返回 0 表示不是好友。
in_room(user_id,room_id)
-
位置
- server\util\database\__init__.py
-
參數(shù)
- user_id 為待檢查用戶
- room_id 為待檢查群聊號
-
功能
判斷 user_id 用戶是否在 room_id 的群聊中。
-
算法描述
從 room_user 表中查詢有無兩者建立關(guān)系的一行,若沒有,則返回 0 表示不是不在群聊中。
add_to_room(user_id,room_id)
-
位置
- server\util\database\__init__.py
-
參數(shù)
- user_id 為待檢查用戶
- room_id 為待檢查群聊號
-
功能
將用戶 id 為 user_id 的用戶加入到 room_id 的群聊中。
-
算法描述
數(shù)據(jù)庫 insert 將 user_id 插入到 room_id 的 room_user 表中。
get_room_members_id(room_id)
-
位置
- server\util\database\__init__.py
-
參數(shù)
- room_id 為待檢查群聊號
-
功能
獲取群聊中的所有用戶 id。
-
算法描述
select 逐一查詢,將結(jié)果返回入列表。
add_to_chat_history(user_id,target_id,target_type,data,sent)
-
位置
- server\util\database\__init__.py
-
參數(shù)
- user_Id 是發(fā)送者 id
- target_id 是目標用戶 id
- target_type 是數(shù)據(jù)類型,0 表示文本信息,1 表示圖像文件信息
- data 是傳輸存儲的數(shù)據(jù)
- sent 標志位記錄是否發(fā)送成功。若為 0,下一次還會再發(fā)送。
-
功能
將聊天信息加入到正確用戶的數(shù)據(jù)庫中。
-
算法描述
將相關(guān)信息 insert 入表 chat_history 中。
get_chat_history(user_id)
-
位置
- server\util\database\__init__.py
-
參數(shù)
- user_id 為待檢查用戶
-
功能
獲取 user_id 用戶的聊天記錄。
-
算法描述
select 查詢并更新 sent 標志位。
實現(xiàn)效果
注冊頁面
對輸入的用戶名、密碼、郵箱、確認密碼等進行檢查,用戶名和密碼限制輸入非法字符,郵箱限制輸入為 xxx@xxx.xxxmailto:xxx@xxx.xxx 形式,同時限制輸入的用戶名長度不大于 8 個,允許中文輸入。
登錄頁面
對輸入的用戶名和密碼進行檢查,限制輸入非法字符,同 時限制輸入的用戶名長度不大于 8 個,允許中文輸入。
好友列表
好友列表會顯示所有好友的在線狀態(tài)、IP 地址、端口號、最新消息和未讀消息, 好友列表根據(jù)用戶離線、在線情況對列表進行刷新,將在線和最近聊天用戶置頂。
添加好友
添加好友時需要輸入用戶名,同時會對輸入的信息進行合法性檢查,不能添加自 己為好友。
要添加的好友用戶名必須為已經(jīng)注冊的用戶,否則會顯示用戶名不存在。
輸入正確用戶名并點擊 OK 后,會顯示好友請求已發(fā)送。
如果在線,會顯示好友請求,點擊 YSE 后,會在雙方的好友列表中添加;點擊 NO 后兩個用戶無法成為好友;點擊 cancle 后,下次登陸時會再次彈出好友請求框。
刪除好友
與添加好友相同,需要輸入用戶名,同時會對輸入的信息進行合法性檢查,不能刪 除自己。
不能刪除好友列表中不存在的用戶。
輸入正確用戶名并點擊 OK 后,會顯示成功刪除好友,并且好友列表進行刷新刪除 剛剛刪除的好友信息,刪除用戶也會對好友列表進行刷新,即雙方向刪除。
添加群聊
需要輸入要添加的群聊的群號,同時會對輸入的信息進行合法性檢查,如果群號 不存在則無法添加,同樣如果已經(jīng)在群聊中,會顯示已經(jīng)在群聊中。
創(chuàng)建群聊
需要輸入創(chuàng)建的群聊的群名稱,同時會對輸入的信息進行合法性檢查,如果群名 稱已存在,則無法創(chuàng)建,創(chuàng)建成功后會分配一個群號。
群聊界面
在群聊界面中,用戶可以直接發(fā)送消息,也可以點擊發(fā)送文件按鈕發(fā)送文件,聊天 框會顯示用戶名、發(fā)送時間和消息內(nèi)容,不同用戶名顏色不同,歷史消息會進行緩 存,用戶再次打開聊天框時會直接顯示。
用戶可以根據(jù)自己的習(xí)慣更改字體大小。
用戶可以根據(jù)自己的習(xí)慣更改字體顏色。
用戶聊天界面
和群聊界面基本相同,用戶聊天內(nèi)容會緩存到客戶端文件夾中,發(fā)送的文件會存 儲到專用文件夾中,如下圖。
待優(yōu)化
正常信息交互流程,server 端會返回加密數(shù)據(jù),此時 client 會一直等待接收 (while true)。如果發(fā)的太大,server 端加密不出來,client 一直監(jiān)聽,導(dǎo)致 client 無法再次發(fā)起操作。
以正常的發(fā)送圖片數(shù)據(jù)抓包為例子,server 會不斷接收,然后做加密。
總結(jié)
以上是生活随笔為你收集整理的基于python的安全即时通讯系统的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: sdio卡识别与sd的异同
- 下一篇: websocket python爬虫_p