dimp 2.2.2__tar.gz → 2.3.1__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.
- dimp-2.3.1/LICENSE +21 -0
- dimp-2.3.1/PKG-INFO +248 -0
- {dimp-2.2.2 → dimp-2.3.1}/dimp/__init__.py +10 -1
- {dimp-2.2.2 → dimp-2.3.1}/dimp/crypto/__init__.py +9 -0
- dimp-2.3.1/dimp/crypto/algorithms.py +57 -0
- {dimp-2.2.2 → dimp-2.3.1}/dimp/crypto/keys.py +4 -3
- {dimp-2.2.2 → dimp-2.3.1}/dimp/crypto/ted.py +27 -22
- {dimp-2.2.2 → dimp-2.3.1}/dimp/dkd/base.py +9 -8
- {dimp-2.2.2 → dimp-2.3.1}/dimp/dkd/commands.py +24 -25
- {dimp-2.2.2 → dimp-2.3.1}/dimp/dkd/contents.py +34 -31
- {dimp-2.2.2 → dimp-2.3.1}/dimp/dkd/files.py +6 -7
- {dimp-2.2.2 → dimp-2.3.1}/dimp/dkd/group_admins.py +48 -12
- {dimp-2.2.2 → dimp-2.3.1}/dimp/dkd/groups.py +7 -7
- {dimp-2.2.2 → dimp-2.3.1}/dimp/dkd/money.py +15 -7
- {dimp-2.2.2 → dimp-2.3.1}/dimp/dkd/quote.py +13 -8
- {dimp-2.2.2 → dimp-2.3.1}/dimp/dkd/receipt.py +1 -1
- {dimp-2.2.2 → dimp-2.3.1}/dimp/mkm/__init__.py +3 -0
- {dimp-2.2.2 → dimp-2.3.1}/dimp/mkm/docs.py +5 -5
- {dimp-2.2.2 → dimp-2.3.1}/dimp/mkm/document.py +3 -13
- {dimp-2.2.2 → dimp-2.3.1}/dimp/mkm/meta.py +8 -9
- {dimp-2.2.2 → dimp-2.3.1}/dimp/msg/base.py +1 -1
- {dimp-2.2.2 → dimp-2.3.1}/dimp/msg/envelope.py +3 -3
- {dimp-2.2.2 → dimp-2.3.1}/dimp/msg/instant.py +6 -6
- {dimp-2.2.2 → dimp-2.3.1}/dimp/protocol/__init__.py +3 -0
- {dimp-2.2.2 → dimp-2.3.1}/dimp/protocol/commands.py +15 -15
- {dimp-2.2.2 → dimp-2.3.1}/dimp/protocol/contents.py +8 -44
- {dimp-2.2.2 → dimp-2.3.1}/dimp/protocol/files.py +11 -10
- {dimp-2.2.2 → dimp-2.3.1}/dimp/protocol/groups.py +28 -10
- {dimp-2.2.2 → dimp-2.3.1}/dimp/protocol/money.py +6 -5
- {dimp-2.2.2 → dimp-2.3.1}/dimp/protocol/quote.py +3 -21
- {dimp-2.2.2 → dimp-2.3.1}/dimp/protocol/receipt.py +1 -1
- dimp-2.3.1/dimp/protocol/types.py +177 -0
- dimp-2.3.1/dimp.egg-info/PKG-INFO +248 -0
- {dimp-2.2.2 → dimp-2.3.1}/dimp.egg-info/SOURCES.txt +4 -1
- dimp-2.3.1/dimp.egg-info/requires.txt +2 -0
- {dimp-2.2.2 → dimp-2.3.1}/setup.py +3 -3
- dimp-2.2.2/PKG-INFO +0 -248
- dimp-2.2.2/dimp.egg-info/PKG-INFO +0 -248
- dimp-2.2.2/dimp.egg-info/requires.txt +0 -2
- {dimp-2.2.2 → dimp-2.3.1}/README.md +0 -0
- {dimp-2.2.2 → dimp-2.3.1}/dimp/crypto/pnf.py +0 -0
- {dimp-2.2.2 → dimp-2.3.1}/dimp/dkd/__init__.py +0 -0
- {dimp-2.2.2 → dimp-2.3.1}/dimp/msg/__init__.py +0 -0
- {dimp-2.2.2 → dimp-2.3.1}/dimp/msg/reliable.py +0 -0
- {dimp-2.2.2 → dimp-2.3.1}/dimp/msg/secure.py +0 -0
- {dimp-2.2.2 → dimp-2.3.1}/dimp/plugins/__init__.py +0 -0
- {dimp-2.2.2 → dimp-2.3.1}/dimp/plugins/cmd.py +0 -0
- {dimp-2.2.2 → dimp-2.3.1}/dimp/protocol/docs.py +0 -0
- {dimp-2.2.2 → dimp-2.3.1}/dimp/protocol/helpers.py +0 -0
- {dimp-2.2.2 → dimp-2.3.1}/dimp.egg-info/dependency_links.txt +0 -0
- {dimp-2.2.2 → dimp-2.3.1}/dimp.egg-info/top_level.txt +0 -0
- {dimp-2.2.2 → dimp-2.3.1}/setup.cfg +0 -0
dimp-2.3.1/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2019 Albert Moky
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
dimp-2.3.1/PKG-INFO
ADDED
|
@@ -0,0 +1,248 @@
|
|
|
1
|
+
Metadata-Version: 2.1
|
|
2
|
+
Name: dimp
|
|
3
|
+
Version: 2.3.1
|
|
4
|
+
Summary: Decentralized Instant Messaging Protocol
|
|
5
|
+
Home-page: https://github.com/dimchat/core-py
|
|
6
|
+
Author: Albert Moky
|
|
7
|
+
Author-email: albert.moky@gmail.com
|
|
8
|
+
License: MIT
|
|
9
|
+
Classifier: Programming Language :: Python :: 3
|
|
10
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
11
|
+
Classifier: Operating System :: OS Independent
|
|
12
|
+
Description-Content-Type: text/markdown
|
|
13
|
+
License-File: LICENSE
|
|
14
|
+
|
|
15
|
+
# Decentralized Instant Messaging Protocol (Python)
|
|
16
|
+
|
|
17
|
+
[](https://github.com/dimchat/core-py/blob/master/LICENSE)
|
|
18
|
+
[](https://github.com/dimchat/core-py/pulls)
|
|
19
|
+
[](https://github.com/dimchat/core-py/wiki)
|
|
20
|
+
[](https://github.com/dimchat/core-py/issues)
|
|
21
|
+
[](https://github.com/dimchat/core-py/archive/refs/heads/main.zip)
|
|
22
|
+
[](https://github.com/dimchat/core-py/tags)
|
|
23
|
+
[](https://pypi.org/project/dimp)
|
|
24
|
+
|
|
25
|
+
[](https://github.com/dimchat/core-py/watchers)
|
|
26
|
+
[](https://github.com/dimchat/core-py/forks)
|
|
27
|
+
[](https://github.com/dimchat/core-py/stargazers)
|
|
28
|
+
[](https://github.com/orgs/dimchat/followers)
|
|
29
|
+
|
|
30
|
+
## Dependencies
|
|
31
|
+
|
|
32
|
+
| Name | Version | Description |
|
|
33
|
+
|------|---------|-------------|
|
|
34
|
+
| [Ming Ke Ming (名可名)](https://github.com/dimchat/mkm-py) | [](https://pypi.org/project/mkm) | Decentralized User Identity Authentication |
|
|
35
|
+
| [Dao Ke Dao (道可道)](https://github.com/dimchat/dkd-py) | [](https://pypi.org/project/dkd) | Universal Message Module |
|
|
36
|
+
|
|
37
|
+
## Examples
|
|
38
|
+
|
|
39
|
+
### extends Command
|
|
40
|
+
|
|
41
|
+
* _Handshake Command Protocol_
|
|
42
|
+
0. (C-S) handshake start
|
|
43
|
+
1. (S-C) handshake again with new session
|
|
44
|
+
2. (C-S) handshake restart with new session
|
|
45
|
+
3. (S-C) handshake success
|
|
46
|
+
|
|
47
|
+
```python
|
|
48
|
+
from enum import IntEnum
|
|
49
|
+
from typing import Optional, Any, Dict
|
|
50
|
+
|
|
51
|
+
from dimp import Command, BaseCommand
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
class HandshakeState(IntEnum):
|
|
55
|
+
Start = 0 # C -> S, without session key(or session expired)
|
|
56
|
+
Again = 1 # S -> C, with new session key
|
|
57
|
+
Restart = 2 # C -> S, with new session key
|
|
58
|
+
Success = 3 # S -> C, handshake accepted
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
class HandshakeCommand(BaseCommand):
|
|
62
|
+
"""
|
|
63
|
+
Handshake Command
|
|
64
|
+
~~~~~~~~~~~~~~~~~
|
|
65
|
+
|
|
66
|
+
data format: {
|
|
67
|
+
type : 0x88,
|
|
68
|
+
sn : 123,
|
|
69
|
+
|
|
70
|
+
command : "handshake", // command name
|
|
71
|
+
title : "Hello world!", // "DIM?", "DIM!"
|
|
72
|
+
session : "{SESSION_ID}", // session key
|
|
73
|
+
}
|
|
74
|
+
"""
|
|
75
|
+
HANDSHAKE = 'handshake'
|
|
76
|
+
|
|
77
|
+
def __init__(self, content: Dict[str, Any] = None, title: str = None, session: str = None):
|
|
78
|
+
if content is None:
|
|
79
|
+
# 1. new command with title & session key
|
|
80
|
+
assert title is not None, 'handshake command error: %s' % session
|
|
81
|
+
cmd = self.HANDSHAKE
|
|
82
|
+
super().__init__(cmd=cmd)
|
|
83
|
+
self['title'] = title
|
|
84
|
+
self['message'] = title # TODO: remove after all clients upgraded
|
|
85
|
+
if session is not None:
|
|
86
|
+
self['session'] = session
|
|
87
|
+
else:
|
|
88
|
+
# 2. command info from network
|
|
89
|
+
assert title is None and session is None, 'params error: %s, %s, %s' % (content, title, session)
|
|
90
|
+
super().__init__(content)
|
|
91
|
+
|
|
92
|
+
@property
|
|
93
|
+
def title(self) -> str:
|
|
94
|
+
# TODO: modify after all clients upgraded
|
|
95
|
+
text = self.get_str(key='title', default=None)
|
|
96
|
+
if text is None:
|
|
97
|
+
# compatible with v1.0
|
|
98
|
+
text = self.get_str(key='message', default='')
|
|
99
|
+
return text
|
|
100
|
+
|
|
101
|
+
@property
|
|
102
|
+
def session(self) -> Optional[str]:
|
|
103
|
+
return self.get_str(key='session', default=None)
|
|
104
|
+
|
|
105
|
+
@property
|
|
106
|
+
def state(self) -> HandshakeState:
|
|
107
|
+
return handshake_state(title=self.title, session=self.session)
|
|
108
|
+
|
|
109
|
+
@classmethod
|
|
110
|
+
def offer(cls, session: str = None) -> Command:
|
|
111
|
+
"""
|
|
112
|
+
Create client-station handshake offer
|
|
113
|
+
|
|
114
|
+
:param session: Old session key
|
|
115
|
+
:return: HandshakeCommand object
|
|
116
|
+
"""
|
|
117
|
+
return HandshakeCommand(title='Hello world!', session=session)
|
|
118
|
+
|
|
119
|
+
@classmethod
|
|
120
|
+
def ask(cls, session: str) -> Command:
|
|
121
|
+
"""
|
|
122
|
+
Create station-client handshake again with new session
|
|
123
|
+
|
|
124
|
+
:param session: New session key
|
|
125
|
+
:return: HandshakeCommand object
|
|
126
|
+
"""
|
|
127
|
+
return HandshakeCommand(title='DIM?', session=session)
|
|
128
|
+
|
|
129
|
+
@classmethod
|
|
130
|
+
def accepted(cls, session: str = None) -> Command:
|
|
131
|
+
"""
|
|
132
|
+
Create station-client handshake success notice
|
|
133
|
+
|
|
134
|
+
:return: HandshakeCommand object
|
|
135
|
+
"""
|
|
136
|
+
return HandshakeCommand(title='DIM!', session=session)
|
|
137
|
+
|
|
138
|
+
start = offer # (1. C->S) first handshake, without session
|
|
139
|
+
again = ask # (2. S->C) ask client to handshake with new session key
|
|
140
|
+
restart = offer # (3. C->S) handshake with new session key
|
|
141
|
+
success = accepted # (4. S->C) notice the client that handshake accepted
|
|
142
|
+
|
|
143
|
+
|
|
144
|
+
def handshake_state(title: str, session: str = None) -> HandshakeState:
|
|
145
|
+
# Server -> Client
|
|
146
|
+
if title == 'DIM!': # or title == 'OK!':
|
|
147
|
+
return HandshakeState.Success
|
|
148
|
+
if title == 'DIM?':
|
|
149
|
+
return HandshakeState.Again
|
|
150
|
+
# Client -> Server: "Hello world!"
|
|
151
|
+
if session is None or len(session) == 0:
|
|
152
|
+
return HandshakeState.Start
|
|
153
|
+
else:
|
|
154
|
+
return HandshakeState.Restart
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
### extends Content
|
|
158
|
+
|
|
159
|
+
```python
|
|
160
|
+
from abc import ABC, abstractmethod
|
|
161
|
+
from typing import Any, Dict
|
|
162
|
+
|
|
163
|
+
from dimp import ContentType
|
|
164
|
+
from dimp import Content
|
|
165
|
+
from dimp import BaseContent
|
|
166
|
+
|
|
167
|
+
|
|
168
|
+
class CustomizedContent(Content, ABC):
|
|
169
|
+
"""
|
|
170
|
+
Application Customized message
|
|
171
|
+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
172
|
+
|
|
173
|
+
data format: {
|
|
174
|
+
type : 0xCC,
|
|
175
|
+
sn : 123,
|
|
176
|
+
|
|
177
|
+
app : "{APP_ID}", // application (e.g.: "chat.dim.sechat")
|
|
178
|
+
mod : "{MODULE}", // module name (e.g.: "drift_bottle")
|
|
179
|
+
act : "{ACTION}", // action name (e.g.: "throw")
|
|
180
|
+
extra : info // action parameters
|
|
181
|
+
}
|
|
182
|
+
"""
|
|
183
|
+
|
|
184
|
+
@property
|
|
185
|
+
@abstractmethod
|
|
186
|
+
def application(self) -> str:
|
|
187
|
+
""" App ID """
|
|
188
|
+
raise NotImplemented
|
|
189
|
+
|
|
190
|
+
@property
|
|
191
|
+
@abstractmethod
|
|
192
|
+
def module(self) -> str:
|
|
193
|
+
""" Module Name """
|
|
194
|
+
raise NotImplemented
|
|
195
|
+
|
|
196
|
+
@property
|
|
197
|
+
@abstractmethod
|
|
198
|
+
def action(self) -> str:
|
|
199
|
+
""" Action Name """
|
|
200
|
+
raise NotImplemented
|
|
201
|
+
|
|
202
|
+
@classmethod
|
|
203
|
+
def create(cls, app: str, mod: str, act: str):
|
|
204
|
+
return AppCustomizedContent(app=app, mod=mod, act=act)
|
|
205
|
+
|
|
206
|
+
|
|
207
|
+
class AppCustomizedContent(BaseContent, CustomizedContent):
|
|
208
|
+
|
|
209
|
+
def __init__(self, content: Dict[str, Any] = None,
|
|
210
|
+
msg_type: int = None,
|
|
211
|
+
app: str = None, mod: str = None, act: str = None):
|
|
212
|
+
if content is None:
|
|
213
|
+
# 1. new content with type, application, module & action
|
|
214
|
+
assert app is not None and mod is not None and act is not None, \
|
|
215
|
+
'customized content error: %s, %s, %s, %s' % (msg_type, app, mod, act)
|
|
216
|
+
if msg_type is None:
|
|
217
|
+
msg_type = ContentType.CUSTOMIZED.value
|
|
218
|
+
super().__init__(None, msg_type)
|
|
219
|
+
self['app'] = app
|
|
220
|
+
self['mod'] = mod
|
|
221
|
+
self['act'] = act
|
|
222
|
+
else:
|
|
223
|
+
# 2. content info from network
|
|
224
|
+
assert msg_type is None and app is None and mod is None and act is None, \
|
|
225
|
+
'params error: %s, %s, %s, %s, %s' % (content, msg_type, app, mod, act)
|
|
226
|
+
super().__init__(content)
|
|
227
|
+
|
|
228
|
+
@property # Override
|
|
229
|
+
def application(self) -> str:
|
|
230
|
+
return self.get_str(key='app', default='')
|
|
231
|
+
|
|
232
|
+
@property # Override
|
|
233
|
+
def module(self) -> str:
|
|
234
|
+
return self.get_str(key='mod', default='')
|
|
235
|
+
|
|
236
|
+
@property # Override
|
|
237
|
+
def action(self) -> str:
|
|
238
|
+
return self.get_str(key='act', default='')
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
### extends ID Address
|
|
242
|
+
|
|
243
|
+
* Examples in [dim plugins](https://pypi.org/project/dimplugins)
|
|
244
|
+
|
|
245
|
+
----
|
|
246
|
+
|
|
247
|
+
Copyright © 2018 Albert Moky
|
|
248
|
+
[](https://github.com/moky?tab=followers)
|
|
@@ -52,7 +52,8 @@ __all__ = [
|
|
|
52
52
|
|
|
53
53
|
'URI', 'DateTime',
|
|
54
54
|
|
|
55
|
-
'Converter', '
|
|
55
|
+
'Converter', 'DataConverter', 'BaseConverter',
|
|
56
|
+
'Copier',
|
|
56
57
|
'Wrapper', 'Stringer', 'Mapper',
|
|
57
58
|
'ConstantString', # 'String',
|
|
58
59
|
'Dictionary',
|
|
@@ -102,6 +103,12 @@ __all__ = [
|
|
|
102
103
|
'BaseDataWrapper',
|
|
103
104
|
'BaseFileWrapper',
|
|
104
105
|
|
|
106
|
+
#
|
|
107
|
+
# Algorithm
|
|
108
|
+
#
|
|
109
|
+
'AsymmetricAlgorithms', 'SymmetricAlgorithms',
|
|
110
|
+
'EncodeAlgorithms',
|
|
111
|
+
|
|
105
112
|
#
|
|
106
113
|
# MingKeMing
|
|
107
114
|
#
|
|
@@ -125,6 +132,8 @@ __all__ = [
|
|
|
125
132
|
'BaseMeta',
|
|
126
133
|
'BaseDocument', 'BaseVisa', 'BaseBulletin',
|
|
127
134
|
|
|
135
|
+
'MetaType', 'DocumentType',
|
|
136
|
+
|
|
128
137
|
#
|
|
129
138
|
# DaoKeDao
|
|
130
139
|
#
|
|
@@ -30,6 +30,9 @@
|
|
|
30
30
|
|
|
31
31
|
from mkm.crypto import *
|
|
32
32
|
|
|
33
|
+
from .algorithms import AsymmetricAlgorithms, SymmetricAlgorithms
|
|
34
|
+
from .algorithms import EncodeAlgorithms
|
|
35
|
+
|
|
33
36
|
from .keys import BaseKey, BaseSymmetricKey
|
|
34
37
|
from .keys import BaseAsymmetricKey, BasePublicKey, BasePrivateKey
|
|
35
38
|
|
|
@@ -57,6 +60,12 @@ __all__ = [
|
|
|
57
60
|
|
|
58
61
|
'SymmetricKeyFactory', 'PrivateKeyFactory', 'PublicKeyFactory',
|
|
59
62
|
|
|
63
|
+
#
|
|
64
|
+
# Algorithm
|
|
65
|
+
#
|
|
66
|
+
'AsymmetricAlgorithms', 'SymmetricAlgorithms',
|
|
67
|
+
'EncodeAlgorithms',
|
|
68
|
+
|
|
60
69
|
#
|
|
61
70
|
# Base Keys
|
|
62
71
|
#
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
#
|
|
3
|
+
# DIMP : Decentralized Instant Messaging Protocol
|
|
4
|
+
#
|
|
5
|
+
# Written in 2025 by Moky <albert.moky@gmail.com>
|
|
6
|
+
#
|
|
7
|
+
# ==============================================================================
|
|
8
|
+
# MIT License
|
|
9
|
+
#
|
|
10
|
+
# Copyright (c) 2025 Albert Moky
|
|
11
|
+
#
|
|
12
|
+
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
13
|
+
# of this software and associated documentation files (the "Software"), to deal
|
|
14
|
+
# in the Software without restriction, including without limitation the rights
|
|
15
|
+
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
16
|
+
# copies of the Software, and to permit persons to whom the Software is
|
|
17
|
+
# furnished to do so, subject to the following conditions:
|
|
18
|
+
#
|
|
19
|
+
# The above copyright notice and this permission notice shall be included in all
|
|
20
|
+
# copies or substantial portions of the Software.
|
|
21
|
+
#
|
|
22
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
23
|
+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
24
|
+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
25
|
+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
26
|
+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
27
|
+
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
28
|
+
# SOFTWARE.
|
|
29
|
+
# ==============================================================================
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
class AsymmetricAlgorithms:
|
|
33
|
+
""" Algorithms for Asymmetric Key """
|
|
34
|
+
|
|
35
|
+
RSA = 'RSA' # -- "RSA/ECB/PKCS1Padding", "SHA256withRSA"
|
|
36
|
+
ECC = 'ECC'
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
class SymmetricAlgorithms:
|
|
40
|
+
""" Algorithms for Symmetric Key """
|
|
41
|
+
|
|
42
|
+
AES = 'AES' # -- "AES/CBC/PKCS7Padding"
|
|
43
|
+
DES = 'DES'
|
|
44
|
+
|
|
45
|
+
# Symmetric key algorithm for broadcast message,
|
|
46
|
+
# which will do nothing when en/decoding message data
|
|
47
|
+
PLAIN = 'PLAIN'
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
class EncodeAlgorithms:
|
|
51
|
+
""" Algorithms for Encoding Data """
|
|
52
|
+
|
|
53
|
+
DEFAULT = 'base64'
|
|
54
|
+
|
|
55
|
+
BASE_64 = 'base64'
|
|
56
|
+
BASE_58 = 'base58'
|
|
57
|
+
HEX = 'hex'
|
|
@@ -29,7 +29,7 @@
|
|
|
29
29
|
# ==============================================================================
|
|
30
30
|
|
|
31
31
|
from abc import ABC
|
|
32
|
-
from typing import
|
|
32
|
+
from typing import Any, Dict
|
|
33
33
|
|
|
34
34
|
from mkm.types import Dictionary
|
|
35
35
|
from mkm.crypto import CryptographyKey, EncryptKey, DecryptKey, SignKey, VerifyKey
|
|
@@ -58,9 +58,10 @@ class BaseKey(Dictionary, CryptographyKey, ABC):
|
|
|
58
58
|
#
|
|
59
59
|
|
|
60
60
|
@classmethod
|
|
61
|
-
def get_key_algorithm(cls, key: Dict[str, Any]) ->
|
|
61
|
+
def get_key_algorithm(cls, key: Dict[str, Any]) -> str:
|
|
62
62
|
ext = SharedCryptoExtensions()
|
|
63
|
-
|
|
63
|
+
algorithm = ext.helper.get_key_algorithm(key=key, default=None)
|
|
64
|
+
return '' if algorithm is None else algorithm
|
|
64
65
|
|
|
65
66
|
@classmethod
|
|
66
67
|
def match_encrypt_key(cls, encrypt_key: EncryptKey, decrypt_key: DecryptKey) -> bool:
|
|
@@ -33,9 +33,10 @@ from typing import Optional, Any, Dict
|
|
|
33
33
|
from mkm.format import base64_encode, base64_decode
|
|
34
34
|
from mkm.format import base58_encode, base58_decode
|
|
35
35
|
from mkm.format import hex_encode, hex_decode
|
|
36
|
-
from mkm.format import TransportableData
|
|
37
36
|
from mkm.types import Dictionary
|
|
38
37
|
|
|
38
|
+
from .algorithms import EncodeAlgorithms
|
|
39
|
+
|
|
39
40
|
|
|
40
41
|
class BaseDataWrapper(Dictionary):
|
|
41
42
|
"""
|
|
@@ -68,11 +69,11 @@ class BaseDataWrapper(Dictionary):
|
|
|
68
69
|
|
|
69
70
|
# Override
|
|
70
71
|
def __str__(self) -> str:
|
|
71
|
-
text = self.get_str(key='data', default=
|
|
72
|
-
if len(text) == 0:
|
|
73
|
-
return
|
|
74
|
-
alg = self.get_str(key='algorithm', default=
|
|
75
|
-
if alg ==
|
|
72
|
+
text = self.get_str(key='data', default=None)
|
|
73
|
+
if text is None: # or len(text) == 0:
|
|
74
|
+
return ''
|
|
75
|
+
alg = self.get_str(key='algorithm', default=None)
|
|
76
|
+
if alg is None or alg == EncodeAlgorithms.DEFAULT:
|
|
76
77
|
alg = ''
|
|
77
78
|
if len(alg) == 0:
|
|
78
79
|
# 0. "{BASE64_ENCODE}"
|
|
@@ -84,9 +85,9 @@ class BaseDataWrapper(Dictionary):
|
|
|
84
85
|
def encode(self, mime_type: str) -> str:
|
|
85
86
|
""" toString(mimeType) """
|
|
86
87
|
# get encoded data
|
|
87
|
-
text = self.get_str(key='data', default=
|
|
88
|
-
if len(text) == 0:
|
|
89
|
-
return
|
|
88
|
+
text = self.get_str(key='data', default=None)
|
|
89
|
+
if text is None: # or len(text) == 0:
|
|
90
|
+
return ''
|
|
90
91
|
alg = self.algorithm
|
|
91
92
|
# 2. "data:image/png;base64,{BASE64_ENCODE}"
|
|
92
93
|
return 'data:%s;%s,%s' % (mime_type, alg, text)
|
|
@@ -97,14 +98,14 @@ class BaseDataWrapper(Dictionary):
|
|
|
97
98
|
|
|
98
99
|
@property
|
|
99
100
|
def algorithm(self) -> str:
|
|
100
|
-
alg = self.get_str(key='algorithm', default=
|
|
101
|
-
if len(alg) == 0:
|
|
102
|
-
alg =
|
|
101
|
+
alg = self.get_str(key='algorithm', default=None)
|
|
102
|
+
if alg is None or len(alg) == 0:
|
|
103
|
+
alg = EncodeAlgorithms.DEFAULT
|
|
103
104
|
return alg
|
|
104
105
|
|
|
105
106
|
@algorithm.setter
|
|
106
107
|
def algorithm(self, name: str):
|
|
107
|
-
if name is None: # or name ==
|
|
108
|
+
if name is None: # or name == EncodeAlgorithms.DEFAULT:
|
|
108
109
|
self.pop('algorithm', None)
|
|
109
110
|
else:
|
|
110
111
|
self['algorithm'] = name
|
|
@@ -117,14 +118,17 @@ class BaseDataWrapper(Dictionary):
|
|
|
117
118
|
def data(self) -> Optional[bytes]:
|
|
118
119
|
binary = self.__data
|
|
119
120
|
if binary is None:
|
|
120
|
-
text = self.get_str(key='data', default=
|
|
121
|
-
if len(text)
|
|
121
|
+
text = self.get_str(key='data', default=None)
|
|
122
|
+
if text is None or len(text) == 0:
|
|
123
|
+
assert False, 'TED data empty: %s' % self.dictionary
|
|
124
|
+
# return None
|
|
125
|
+
else:
|
|
122
126
|
alg = self.algorithm
|
|
123
|
-
if alg ==
|
|
127
|
+
if alg == EncodeAlgorithms.BASE_64:
|
|
124
128
|
binary = base64_decode(string=text)
|
|
125
|
-
elif alg ==
|
|
129
|
+
elif alg == EncodeAlgorithms.BASE_58:
|
|
126
130
|
binary = base58_decode(string=text)
|
|
127
|
-
elif alg ==
|
|
131
|
+
elif alg == EncodeAlgorithms.HEX:
|
|
128
132
|
binary = hex_decode(string=text)
|
|
129
133
|
else:
|
|
130
134
|
assert False, 'data algorithm not support: %s' % alg
|
|
@@ -137,13 +141,14 @@ class BaseDataWrapper(Dictionary):
|
|
|
137
141
|
self.pop('data', None)
|
|
138
142
|
else:
|
|
139
143
|
alg = self.algorithm
|
|
140
|
-
if alg ==
|
|
144
|
+
if alg == EncodeAlgorithms.BASE_64:
|
|
141
145
|
text = base64_encode(data=binary)
|
|
142
|
-
elif alg ==
|
|
146
|
+
elif alg == EncodeAlgorithms.BASE_58:
|
|
143
147
|
text = base58_encode(data=binary)
|
|
144
|
-
elif alg ==
|
|
148
|
+
elif alg == EncodeAlgorithms.HEX:
|
|
145
149
|
text = hex_encode(data=binary)
|
|
146
150
|
else:
|
|
147
|
-
|
|
151
|
+
raise ArithmeticError('data algorithm not support: %s' % alg)
|
|
152
|
+
# assert False, 'data algorithm not support: %s' % alg
|
|
148
153
|
self['data'] = text
|
|
149
154
|
self.__data = binary
|
|
@@ -33,10 +33,11 @@ from typing import Optional, Any, Dict
|
|
|
33
33
|
from mkm.types import DateTime
|
|
34
34
|
from mkm.types import Dictionary
|
|
35
35
|
from mkm import ID
|
|
36
|
-
from dkd import
|
|
36
|
+
from dkd import Content
|
|
37
37
|
from dkd import InstantMessage
|
|
38
38
|
from dkd.plugins import SharedMessageExtensions
|
|
39
39
|
|
|
40
|
+
from ..protocol import ContentType
|
|
40
41
|
from ..protocol import Command
|
|
41
42
|
|
|
42
43
|
from ..plugins import SharedCommandExtensions
|
|
@@ -52,11 +53,11 @@ from ..plugins import SharedCommandExtensions
|
|
|
52
53
|
|
|
53
54
|
class BaseContent(Dictionary, Content):
|
|
54
55
|
|
|
55
|
-
def __init__(self, content: Dict[str, Any] = None, msg_type:
|
|
56
|
+
def __init__(self, content: Dict[str, Any] = None, msg_type: str = None):
|
|
56
57
|
# check parameters
|
|
57
58
|
if content is None:
|
|
58
59
|
# 1. new content with type
|
|
59
|
-
assert msg_type is not None and msg_type > 0, 'content type error: %s' % msg_type
|
|
60
|
+
assert msg_type is not None and len(msg_type) > 0, 'content type error: %s' % msg_type
|
|
60
61
|
time = DateTime.now()
|
|
61
62
|
sn = InstantMessage.generate_serial_number(msg_type, time)
|
|
62
63
|
content = {
|
|
@@ -77,11 +78,11 @@ class BaseContent(Dictionary, Content):
|
|
|
77
78
|
self.__time = time
|
|
78
79
|
|
|
79
80
|
@property # Override
|
|
80
|
-
def type(self) ->
|
|
81
|
+
def type(self) -> str:
|
|
81
82
|
""" message content type: text, image, ... """
|
|
82
83
|
if self.__type is None:
|
|
83
84
|
ext = SharedMessageExtensions()
|
|
84
|
-
self.__type = ext.helper.get_content_type(content=self.dictionary, default=
|
|
85
|
+
self.__type = ext.helper.get_content_type(content=self.dictionary, default='')
|
|
85
86
|
# self.__type = self.get_int(key='type', default=0)
|
|
86
87
|
return self.__type
|
|
87
88
|
|
|
@@ -114,18 +115,18 @@ class BaseContent(Dictionary, Content):
|
|
|
114
115
|
|
|
115
116
|
class BaseCommand(BaseContent, Command):
|
|
116
117
|
|
|
117
|
-
def __init__(self, content: Dict[str, Any] = None, msg_type:
|
|
118
|
+
def __init__(self, content: Dict[str, Any] = None, msg_type: str = None, cmd: str = None):
|
|
118
119
|
# check parameters
|
|
119
120
|
if content is None:
|
|
120
121
|
# 1. new command with type & name
|
|
121
122
|
if msg_type is None:
|
|
122
|
-
msg_type = ContentType.COMMAND
|
|
123
|
+
msg_type = ContentType.COMMAND
|
|
123
124
|
assert cmd is not None and len(cmd) > 0, 'command name should not empty'
|
|
124
125
|
super().__init__(None, msg_type)
|
|
125
126
|
self['command'] = cmd
|
|
126
127
|
else:
|
|
127
128
|
# 2. command info from network
|
|
128
|
-
assert msg_type is None and cmd is None, 'params error: %
|
|
129
|
+
assert msg_type is None and cmd is None, 'params error: %s, %s' % (msg_type, cmd)
|
|
129
130
|
super().__init__(content)
|
|
130
131
|
|
|
131
132
|
@property # Override
|