Add editing
This commit is contained in:
		
							parent
							
								
									fe7715abb5
								
							
						
					
					
						commit
						c1303a1a66
					
				
					 2 changed files with 184 additions and 87 deletions
				
			
		
							
								
								
									
										51
									
								
								README.md
									
										
									
									
									
								
							
							
						
						
									
										51
									
								
								README.md
									
										
									
									
									
								
							|  | @ -11,8 +11,8 @@ or YAML, and then extended to accept JSON or YAML to write a profile. | ||||||
| ## Usage | ## Usage | ||||||
| 
 | 
 | ||||||
| Reads a tox profile and prints out information on what's in there to stderr. | Reads a tox profile and prints out information on what's in there to stderr. | ||||||
| Call it with one argument, the filename of the profile for the decrypt or info | Call it with one argument, the filename of the profile for the decrypt, edit | ||||||
| commands, or the filename of the nodes file for the nodes command. | or info commands, or the filename of the nodes file for the nodes command. | ||||||
| 
 | 
 | ||||||
| 3 commands are supported: | 3 commands are supported: | ||||||
| 1. ```--command decrypt``` decrypts the profile and writes to the result | 1. ```--command decrypt``` decrypts the profile and writes to the result | ||||||
|  | @ -52,13 +52,24 @@ Optional arguments: | ||||||
| 
 | 
 | ||||||
| ```info``` will output the profile on stdout, or to a file with ```--output``` | ```info``` will output the profile on stdout, or to a file with ```--output``` | ||||||
| 
 | 
 | ||||||
| Choose one of ```{info,repr,yaml,json,pprint}``` | Choose one of ```{info,repr,yaml,json,pprint,save}``` | ||||||
| for the format for info command. | for the format for info command. | ||||||
| 
 | 
 | ||||||
| Choose one of ```{nmap_udp,nmap_tcp}``` | Choose one of ```{nmap_udp,nmap_tcp}``` | ||||||
| to run tests using ```nmap``` for the ```DHT``` and ```TCP_RELAY``` | to run tests using ```nmap``` for the ```DHT``` and ```TCP_RELAY``` | ||||||
| sections of the profile. Reguires ```nmap``` and uses ```sudo```. | sections of the profile. Reguires ```nmap``` and uses ```sudo```. | ||||||
| 
 | 
 | ||||||
|  | #### Saving a copy | ||||||
|  | 
 | ||||||
|  | The code now can generate a saved copy of the profile as it parses the profile. | ||||||
|  | Use the command ```--command info --info save``` with ```--output``` | ||||||
|  | and a filename, to process the file with info to stderr, and it will | ||||||
|  | save an copy of the file to the  ```--output``` (unencrypted). | ||||||
|  | 
 | ||||||
|  | It may be shorter than the original profile by up to 512 bytes, as the | ||||||
|  | original toxic profile is padded at the end with nulls (or maybe in the | ||||||
|  | decryption).  | ||||||
|  | 
 | ||||||
| ### --command nodes | ### --command nodes | ||||||
| 
 | 
 | ||||||
| Takes a DHTnodes.json file as an argument. | Takes a DHTnodes.json file as an argument. | ||||||
|  | @ -74,6 +85,22 @@ nodes. Reguires ```nmap``` and uses ```sudo```. | ||||||
| 
 | 
 | ||||||
| Decrypt a profile. | Decrypt a profile. | ||||||
| 
 | 
 | ||||||
|  | ### --command edit | ||||||
|  | 
 | ||||||
|  | The code now can generate an edited copy of the profile. | ||||||
|  | Use the command ```--command edit --edit section,key,val``` with | ||||||
|  | ```--output``` and a filename, to process the file with info to stderr, | ||||||
|  | and it will save an copy of the edited file to the | ||||||
|  | ```--output``` file (unencrypted). There's not much editing yet; give | ||||||
|  | ```--command edit --edit help``` to get a list of what Available Sections, | ||||||
|  | and Supported Quads (section,num,key,type) that can be edited. | ||||||
|  | Currently it is: | ||||||
|  | ``` | ||||||
|  | NAME,0,Nick_name,str | ||||||
|  | STATUSMESSAGE,0,Status_message,str | ||||||
|  | STATUS,0,Online_status,int | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
| ## Requirements | ## Requirements | ||||||
| 
 | 
 | ||||||
| If you want to read encrypted profiles, you need to download | If you want to read encrypted profiles, you need to download | ||||||
|  | @ -93,22 +120,20 @@ If you want to write in YAML, you need Python yaml: | ||||||
| If you have coloredlogs installed it will make use of it:  | If you have coloredlogs installed it will make use of it:  | ||||||
| <https://pypi.org/project/coloredlogs/> | <https://pypi.org/project/coloredlogs/> | ||||||
| 
 | 
 | ||||||
|  | For the ```select``` and ```nmap``` commands, the ```jq``` utility is | ||||||
|  | required. It's available in most distros, or <https://stedolan.github.io/jq/> | ||||||
|  | 
 | ||||||
|  | For the ```nmap``` commands, the ```nmap``` utility is | ||||||
|  | required. It's available in most distros, or <https://nmap.org/> | ||||||
|  | 
 | ||||||
| ## Future Directions | ## Future Directions | ||||||
| 
 | 
 | ||||||
|  | This has not been tested on Windwoes, but is should be simple to fix. | ||||||
|  | 
 | ||||||
| Because it's written in Python it is easy to extend to, for example, | Because it's written in Python it is easy to extend to, for example, | ||||||
| rekeying a profile when copying a profile to a new device: | rekeying a profile when copying a profile to a new device: | ||||||
| <https://git.plastiras.org/emdee/tox_profile/wiki/MultiDevice-Announcements-POC> | <https://git.plastiras.org/emdee/tox_profile/wiki/MultiDevice-Announcements-POC> | ||||||
| 
 | 
 | ||||||
| ### Editing - save |  | ||||||
| 
 |  | ||||||
| The code now can generate a saved copy of the profile as it parses the profile. |  | ||||||
| Use the command ```--command save``` with ```--output``` and a filename, |  | ||||||
| to process the file with info to stderr, and it will save an copy of the file |  | ||||||
| to the  ```--output``` (unencrypted). |  | ||||||
| 
 |  | ||||||
| It may be shorter than the original profile by up to 512 bytes, as the |  | ||||||
| original toxic profile is padded at the end with nulls.  So this code |  | ||||||
| can be extended to edit the profile before saving it. |  | ||||||
| 
 | 
 | ||||||
| ## Specification | ## Specification | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -20,7 +20,7 @@ commands, or the filename of the nodes file for the nodes command. | ||||||
| """ | """ | ||||||
|   --output Destination for info/decrypt - defaults to stdout |   --output Destination for info/decrypt - defaults to stdout | ||||||
|   --info default='info', |   --info default='info', | ||||||
|          choices=['info', 'repr', 'yaml','json', 'pprint'] |          choices=['info', 'save', 'repr', 'yaml','json', 'pprint'] | ||||||
|          with --info=info prints info about the profile to stderr |          with --info=info prints info about the profile to stderr | ||||||
|          nmap_udp        - test DHT nodes with nmap |          nmap_udp        - test DHT nodes with nmap | ||||||
|          nmap_tcp        - test TCP_RELAY nodes with nmap |          nmap_tcp        - test TCP_RELAY nodes with nmap | ||||||
|  | @ -90,11 +90,15 @@ except ImportError as e: | ||||||
| 
 | 
 | ||||||
| LOG = logging.getLogger('TSF') | LOG = logging.getLogger('TSF') | ||||||
| 
 | 
 | ||||||
| bHAVE_NMAP = shutil.which('nmap') | # Fix for Windows | ||||||
| sDIR = os.environ.get('TMPDIR', '/tmp') | sDIR = os.environ.get('TMPDIR', '/tmp') | ||||||
| # nodes |  | ||||||
| sTOX_VERSION = "1000002018" | sTOX_VERSION = "1000002018" | ||||||
|  | bHAVE_NMAP = shutil.which('nmap') | ||||||
| bHAVE_JQ = shutil.which('jq') | bHAVE_JQ = shutil.which('jq') | ||||||
|  | bMARK = b'\x00\x00\x00\x00\x1f\x1b\xed\x15' | ||||||
|  | bDEBUG = 'DEBUG' in os.environ and os.environ['DEBUG'] != 0 | ||||||
|  | def trace(s): LOG.log(LOG.level, '+ ' +s) | ||||||
|  | LOG.trace = trace | ||||||
| 
 | 
 | ||||||
| #messenger.c | #messenger.c | ||||||
| MESSENGER_STATE_TYPE_NOSPAMKEYS = 1 | MESSENGER_STATE_TYPE_NOSPAMKEYS = 1 | ||||||
|  | @ -172,6 +176,7 @@ Length  Contents | ||||||
| 8  uint64_t Last seen time | 8  uint64_t Last seen time | ||||||
| 
 | 
 | ||||||
| """ | """ | ||||||
|  |     global sENC | ||||||
|     dStatus = { #  Status  Meaning |     dStatus = { #  Status  Meaning | ||||||
|                0:  'Not a friend', |                0:  'Not a friend', | ||||||
|                1:  'Friend added', |                1:  'Friend added', | ||||||
|  | @ -191,12 +196,12 @@ Length  Contents | ||||||
|         o = delta+1+32+1024+1+2+128; l = 2 |         o = delta+1+32+1024+1+2+128; l = 2 | ||||||
|         nsize = struct.unpack_from(">H", result, o)[0] |         nsize = struct.unpack_from(">H", result, o)[0] | ||||||
|         o = delta+1+32+1024+1+2; l = 128 |         o = delta+1+32+1024+1+2; l = 128 | ||||||
|         name = str(result[o:o+nsize], 'utf-8') |         name = str(result[o:o+nsize], sENC) | ||||||
| 
 | 
 | ||||||
|         o = delta+1+32+1024+1+2+128+2+1007; l = 2 |         o = delta+1+32+1024+1+2+128+2+1007; l = 2 | ||||||
|         msize = struct.unpack_from(">H", result, o)[0] |         msize = struct.unpack_from(">H", result, o)[0] | ||||||
|         o = delta+1+32+1024+1+2+128+2; l = 1007 |         o = delta+1+32+1024+1+2+128+2; l = 1007 | ||||||
|         mame = str(result[o:o+msize], 'utf-8') |         mame = str(result[o:o+msize], sENC) | ||||||
|         LOG.info(f"Friend #{i}  {dStatus[status]} {name} {pk}") |         LOG.info(f"Friend #{i}  {dStatus[status]} {name} {pk}") | ||||||
|         lIN += [{"Status": dStatus[status], |         lIN += [{"Status": dStatus[status], | ||||||
|                  "Name": name, |                  "Name": name, | ||||||
|  | @ -207,6 +212,7 @@ def lProcessGroups(state, index, length, result, label="GROUPS"): | ||||||
|     """ |     """ | ||||||
|     No GROUPS description in spec.html |     No GROUPS description in spec.html | ||||||
|     """ |     """ | ||||||
|  |     global sENC | ||||||
|     lIN = [] |     lIN = [] | ||||||
|     i = 0 |     i = 0 | ||||||
|     if not msgpack: |     if not msgpack: | ||||||
|  | @ -237,7 +243,8 @@ def lProcessGroups(state, index, length, result, label="GROUPS"): | ||||||
|             topic_lock, \ |             topic_lock, \ | ||||||
|             voice_state = state_values |             voice_state = state_values | ||||||
|             LOG.info(f"lProcessGroups #{i} version={version}") |             LOG.info(f"lProcessGroups #{i} version={version}") | ||||||
|             dBINS = {"Version": version} |             dBINS = {"Version": version, | ||||||
|  |                      "Privacy_state": privacy_state} | ||||||
|             lIN += [{"State_values": dBINS}] |             lIN += [{"State_values": dBINS}] | ||||||
| 
 | 
 | ||||||
|             assert len(state_bin) == 5, state_bin |             assert len(state_bin) == 5, state_bin | ||||||
|  | @ -251,7 +258,7 @@ def lProcessGroups(state, index, length, result, label="GROUPS"): | ||||||
|             lIN += [{"State_bin": dBINS}] |             lIN += [{"State_bin": dBINS}] | ||||||
| 
 | 
 | ||||||
|             assert len(topic_info) == 6, topic_info |             assert len(topic_info) == 6, topic_info | ||||||
|             topic_info_topic = str(topic_info[3], 'utf-8') |             topic_info_topic = str(topic_info[3], sENC) | ||||||
|             LOG.info(f"lProcessGroups #{i} topic_info_topic={topic_info_topic}") |             LOG.info(f"lProcessGroups #{i} topic_info_topic={topic_info_topic}") | ||||||
|             dBINS = {"topic_info_topic": topic_info_topic} |             dBINS = {"topic_info_topic": topic_info_topic} | ||||||
|             lIN += [{"Topic_info": dBINS}] |             lIN += [{"Topic_info": dBINS}] | ||||||
|  | @ -290,7 +297,7 @@ def lProcessGroups(state, index, length, result, label="GROUPS"): | ||||||
| 
 | 
 | ||||||
|             assert len(self_info) == 4, self_info |             assert len(self_info) == 4, self_info | ||||||
|             self_nick_len, self_role, self_status, self_nick = self_info |             self_nick_len, self_role, self_status, self_nick = self_info | ||||||
|             self_nick = str(self_nick, 'utf-8') |             self_nick = str(self_nick, sENC) | ||||||
|             LOG.info(f"lProcessGroups #{i} self_nick={self_nick}") |             LOG.info(f"lProcessGroups #{i} self_nick={self_nick}") | ||||||
|             dBINS = {"Self_nick": self_nick} |             dBINS = {"Self_nick": self_nick} | ||||||
|             lIN += [{"Self_info": dBINS}] |             lIN += [{"Self_info": dBINS}] | ||||||
|  | @ -398,8 +405,9 @@ def lProcessDHTnodes(state, index, length, result, label="DHTnode"): | ||||||
|         relay += 1 |         relay += 1 | ||||||
|     return lIN |     return lIN | ||||||
| 
 | 
 | ||||||
| def process_chunk(index, state): | def process_chunk(index, state, oArgs=None): | ||||||
|     global lOUT, bOUT, aOUT |     global lOUT, bOUT, aOUT | ||||||
|  |     global sENC | ||||||
| 
 | 
 | ||||||
|     length = struct.unpack_from("<I", state, index)[0] |     length = struct.unpack_from("<I", state, index)[0] | ||||||
|     data_type = struct.unpack_from("<H", state, index + 4)[0] |     data_type = struct.unpack_from("<H", state, index + 4)[0] | ||||||
|  | @ -409,16 +417,14 @@ def process_chunk(index, state): | ||||||
|     result = state[index + 8:index + 8 + length] |     result = state[index + 8:index + 8 + length] | ||||||
| 
 | 
 | ||||||
|     label = dSTATE_TYPE[data_type] |     label = dSTATE_TYPE[data_type] | ||||||
|  |     if oArgs.command == 'edit' and oArgs.edit: | ||||||
|  |         section,num,key,val = oArgs.edit.split(',',3) | ||||||
|  |      | ||||||
|     diff =  index - len(bOUT) |     diff =  index - len(bOUT) | ||||||
|     if diff: |     if diff > 0: | ||||||
|         LOG.debug(f"PROCESS_CHUNK {label} index={index} bOUT={len(bOUT)} delta={diff} length={length}") |         LOG.warn(f"PROCESS_CHUNK {label} index={index} bOUT={len(bOUT)} delta={diff} length={length}") | ||||||
|     # plan on repacking as we read - this is just a starting point |     elif bDEBUG: | ||||||
|     # We'll add the results back to bOUT to see if we get what we started with. |         LOG.trace(f"PROCESS_CHUNK {label} index={index} bOUT={len(bOUT)} delta={diff} length={length}") | ||||||
|     # Then will will be able to selectively null sections or selectively edit. |  | ||||||
|     bOUT += struct.pack("<I", length) + \ |  | ||||||
|         struct.pack("<H", data_type) + \ |  | ||||||
|         struct.pack("<H", check) + \ |  | ||||||
|         result |  | ||||||
| 
 | 
 | ||||||
|     if data_type == MESSENGER_STATE_TYPE_NOSPAMKEYS: |     if data_type == MESSENGER_STATE_TYPE_NOSPAMKEYS: | ||||||
|         nospam = bin_to_hex(result[0:4]) |         nospam = bin_to_hex(result[0:4]) | ||||||
|  | @ -443,16 +449,28 @@ def process_chunk(index, state): | ||||||
|         lOUT += [{label: lIN}]; aOUT.update({label: lIN}) |         lOUT += [{label: lIN}]; aOUT.update({label: lIN}) | ||||||
| 
 | 
 | ||||||
|     elif data_type == MESSENGER_STATE_TYPE_NAME: |     elif data_type == MESSENGER_STATE_TYPE_NAME: | ||||||
|         name = str(state[index + 8:index + 8 + length], 'utf-8') |         name = str(result, sENC) | ||||||
|         LOG.info(f"{label} Nick_name = " +name) |         LOG.info(f"{label} Nick_name = " +name) | ||||||
|         aIN = {"Nick_name": name} |         aIN = {"Nick_name": name} | ||||||
|         lOUT += [{label: aIN}]; aOUT.update({label: aIN}) |         lOUT += [{label: aIN}]; aOUT.update({label: aIN}) | ||||||
|  |         if oArgs.command == 'edit' and section == label: | ||||||
|  |             ## NAME,0,Nick_name,str | ||||||
|  |             if key == "Nick_name": | ||||||
|  |                 result = bytes(val, sENC) | ||||||
|  |                 length = len(result) | ||||||
|  |                 LOG.info(f"{label} {key} EDITED to {val}") | ||||||
|                  |                  | ||||||
|     elif data_type == MESSENGER_STATE_TYPE_STATUSMESSAGE: |     elif data_type == MESSENGER_STATE_TYPE_STATUSMESSAGE: | ||||||
|         mess = str(state[index + 8:index + 8 + length], 'utf-8') |         mess = str(result, sENC) | ||||||
|         LOG.info(f"{label} StatusMessage = " +mess) |         LOG.info(f"{label} StatusMessage = " +mess) | ||||||
|         aIN = {"Status_message": mess} |         aIN = {"Status_message": mess} | ||||||
|         lOUT += [{label: aIN}]; aOUT.update({label: aIN}) |         lOUT += [{label: aIN}]; aOUT.update({label: aIN}) | ||||||
|  |         if oArgs.command == 'edit' and section == label: | ||||||
|  |             ## STATUSMESSAGE,0,Status_message,str | ||||||
|  |             if key == "Status_message": | ||||||
|  |                 result = bytes(val, sENC) | ||||||
|  |                 length = len(result) | ||||||
|  |                 LOG.info(f"{label} {key} EDITED to {val}") | ||||||
|              |              | ||||||
|     elif data_type == MESSENGER_STATE_TYPE_STATUS: |     elif data_type == MESSENGER_STATE_TYPE_STATUS: | ||||||
|         # 1  uint8_t status (0 = online, 1 = away, 2 = busy) |         # 1  uint8_t status (0 = online, 1 = away, 2 = busy) | ||||||
|  | @ -462,6 +480,12 @@ def process_chunk(index, state): | ||||||
|         LOG.info(f"{label} = " +status) |         LOG.info(f"{label} = " +status) | ||||||
|         aIN = {f"Online_status": status} |         aIN = {f"Online_status": status} | ||||||
|         lOUT += [{"STATUS": aIN}]; aOUT.update({"STATUS": aIN}) |         lOUT += [{"STATUS": aIN}]; aOUT.update({"STATUS": aIN}) | ||||||
|  |         if oArgs.command == 'edit' and section == label: | ||||||
|  |             ## STATUS,0,Online_status,int | ||||||
|  |             if key == "Online_status": | ||||||
|  |                 result = struct.pack(">b", int(val)) | ||||||
|  |                 length = len(result) | ||||||
|  |                 LOG.info(f"{label} {key} EDITED to {val}") | ||||||
| 
 | 
 | ||||||
|     elif data_type == MESSENGER_STATE_TYPE_GROUPS: |     elif data_type == MESSENGER_STATE_TYPE_GROUPS: | ||||||
|         if length > 0: |         if length > 0: | ||||||
|  | @ -495,20 +519,31 @@ def process_chunk(index, state): | ||||||
|         lOUT += [{label: []}]; aOUT.update({label: []}) |         lOUT += [{label: []}]; aOUT.update({label: []}) | ||||||
| 
 | 
 | ||||||
|     elif data_type != MESSENGER_STATE_TYPE_END: |     elif data_type != MESSENGER_STATE_TYPE_END: | ||||||
|         LOG.warn("UNRECOGNIZED datatype={datatype}") |         LOG.error("UNRECOGNIZED datatype={datatype}") | ||||||
|  |         sys.exit(1) | ||||||
|          |          | ||||||
|     else: |     else: | ||||||
|         diff = len(bSAVE) - len(bOUT) |  | ||||||
|         if diff: |  | ||||||
|             # if short repacking as we read - tox_profile is padded with nulls |  | ||||||
|             LOG.debug(f"PROCESS_CHUNK bSAVE={len(bSAVE)} bOUT={len(bOUT)} delta={diff}") |  | ||||||
|      |  | ||||||
|         LOG.info("END") # That's all folks... |         LOG.info("END") # That's all folks... | ||||||
|  |         # drop through | ||||||
|  | 
 | ||||||
|  |     # We repack as we read: or edit as we parse; simply edit result and length. | ||||||
|  |     # We'll add the results back to bOUT to see if we get what we started with. | ||||||
|  |     # Then will will be able to selectively null sections or selectively edit. | ||||||
|  |     assert length == len(result), length | ||||||
|  |     bOUT += struct.pack("<I", length) + \ | ||||||
|  |         struct.pack("<H", data_type) + \ | ||||||
|  |         struct.pack("<H", check) + \ | ||||||
|  |         result | ||||||
|  | 
 | ||||||
|  |     if data_type == MESSENGER_STATE_TYPE_END or \ | ||||||
|  |       index + 8 >= len(state): | ||||||
|  |         diff = len(bSAVE) - len(bOUT) | ||||||
|  |         if oArgs.command != 'edit' and diff > 0: | ||||||
|  |             # if short repacking as we read - tox_profile is padded with nulls | ||||||
|  |             LOG.warn(f"PROCESS_CHUNK bSAVE={len(bSAVE)} bOUT={len(bOUT)} delta={diff}") | ||||||
|         return |         return | ||||||
| 
 | 
 | ||||||
|     # failsafe |     process_chunk(new_index, state, oArgs) | ||||||
|     if index + 8 >= len(state): return |  | ||||||
|     process_chunk(new_index, state) |  | ||||||
| 
 | 
 | ||||||
| def bAreWeConnected(): | def bAreWeConnected(): | ||||||
|     # FixMe: Linux |     # FixMe: Linux | ||||||
|  | @ -631,12 +666,14 @@ def oMainArgparser(_=None): | ||||||
|     parser.add_argument('--output', type=str, default='', |     parser.add_argument('--output', type=str, default='', | ||||||
|                         help='Destination for info/decrypt - defaults to stderr') |                         help='Destination for info/decrypt - defaults to stderr') | ||||||
|     parser.add_argument('--command', type=str, default='info', |     parser.add_argument('--command', type=str, default='info', | ||||||
|                         choices=['info', 'decrypt', 'nodes', 'save'], |                         choices=['info', 'decrypt', 'nodes', 'edit'], | ||||||
|                         # required=True, |                         required=True, | ||||||
|                         help='Action command - default: info') |                         help='Action command - default: info') | ||||||
|  |     parser.add_argument('--edit', type=str, default='', | ||||||
|  |                         help='comma seperated SECTION,key,value - unfinished') | ||||||
|     parser.add_argument('--indent', type=int, default=2, |     parser.add_argument('--indent', type=int, default=2, | ||||||
|                         help='Indent for yaml/json/pprint') |                         help='Indent for yaml/json/pprint') | ||||||
|     choices=['info', 'repr', 'yaml','json', 'pprint'] |     choices=['info', 'save', 'repr', 'yaml','json', 'pprint'] | ||||||
|     if bHAVE_NMAP: choices += ['nmap_tcp', 'nmap_udp', 'nmap_onion'] |     if bHAVE_NMAP: choices += ['nmap_tcp', 'nmap_udp', 'nmap_onion'] | ||||||
|     parser.add_argument('--info', type=str, default='info', |     parser.add_argument('--info', type=str, default='info', | ||||||
|                         choices=choices, |                         choices=choices, | ||||||
|  | @ -652,18 +689,38 @@ def oMainArgparser(_=None): | ||||||
|                         help='Action for nodes command (requires jq)') |                         help='Action for nodes command (requires jq)') | ||||||
|     parser.add_argument('--download_nodes_url', type=str, |     parser.add_argument('--download_nodes_url', type=str, | ||||||
|                         default='https://nodes.tox.chat/json') |                         default='https://nodes.tox.chat/json') | ||||||
|  |     parser.add_argument('--encoding', type=str, default=sENC) | ||||||
|     parser.add_argument('profile', type=str, nargs='?', default=None, |     parser.add_argument('profile', type=str, nargs='?', default=None, | ||||||
|                         help='tox profile file - may be encrypted') |                         help='tox profile file - may be encrypted') | ||||||
|     return parser |     return parser | ||||||
| 
 | 
 | ||||||
|  | # grep '#''#' logging_tox_savefile.py|sed -e 's/.* //' | ||||||
|  | sEDIT_HELP = """ | ||||||
|  | NAME,0,Nick_name,str | ||||||
|  | STATUSMESSAGE,0,Status_message,str | ||||||
|  | STATUS,0,Online_status,int | ||||||
|  | """ | ||||||
|  | 
 | ||||||
|  | global lOUT, bOUT, aOUT, sENC | ||||||
|  | lOUT = [] | ||||||
|  | aOUT = {} | ||||||
|  | bOUT = b'' | ||||||
|  | sENC = 'utf-8' | ||||||
| if __name__ == '__main__': | if __name__ == '__main__': | ||||||
|     lArgv = sys.argv[1:] |     lArgv = sys.argv[1:] | ||||||
|     parser = oMainArgparser() |     parser = oMainArgparser() | ||||||
|     oArgs = parser.parse_args(lArgv) |     oArgs = parser.parse_args(lArgv) | ||||||
|  |     if oArgs.command in ['edit'] and oArgs.edit == 'help': | ||||||
|  |         l = list(dSTATE_TYPE.values()) | ||||||
|  |         l.remove('END') | ||||||
|  |         print('Available Sections: ' +repr(l)) | ||||||
|  |         print('Supported Quads: section,num,key,type ' +sEDIT_HELP) | ||||||
|  |         sys.exit(0) | ||||||
| 
 | 
 | ||||||
|     sFile = oArgs.profile |     sFile = oArgs.profile | ||||||
|     assert os.path.isfile(sFile), sFile |     assert os.path.isfile(sFile), sFile | ||||||
| 
 | 
 | ||||||
|  |     sENC = oArgs.encoding | ||||||
|     vSetupLogging() |     vSetupLogging() | ||||||
| 
 | 
 | ||||||
|     bSAVE = open(sFile, 'rb').read() |     bSAVE = open(sFile, 'rb').read() | ||||||
|  | @ -739,7 +796,7 @@ if __name__ == '__main__': | ||||||
|                         oStream.write(bSAVE) |                         oStream.write(bSAVE) | ||||||
|                     else: |                     else: | ||||||
|                         oStream = sys.stdout |                         oStream = sys.stdout | ||||||
|                         oStream.write(str(bSAVE, 'utf-8')) |                         oStream.write(str(bSAVE, sENC)) | ||||||
|                     iRet = -1 |                     iRet = -1 | ||||||
|                     LOG.info(f"downloaded list of nodes saved to {oStream}") |                     LOG.info(f"downloaded list of nodes saved to {oStream}") | ||||||
| 
 | 
 | ||||||
|  | @ -748,53 +805,68 @@ if __name__ == '__main__': | ||||||
|         elif iRet == 0: |         elif iRet == 0: | ||||||
|             LOG.info(f"{oArgs.nodes} iRet={iRet} to {oArgs.output}") |             LOG.info(f"{oArgs.nodes} iRet={iRet} to {oArgs.output}") | ||||||
| 
 | 
 | ||||||
|     elif oArgs.command in ['save', 'info']: |     elif oArgs.command in ['info', 'edit']: | ||||||
|         if oArgs.command == 'save': |         if oArgs.command in ['edit']: | ||||||
|             assert oArgs.output, "--output required for this command" |             assert oArgs.output, "--output required for this command" | ||||||
|  |             assert oArgs.edit != '', "--edit required for this command" | ||||||
|  |         elif oArgs.command == 'info': | ||||||
|  |             # assert oArgs.info != '', "--info required for this command" | ||||||
|  |             if oArgs.info in ['save', 'yaml', 'json', 'repr', 'pprint']: | ||||||
|  |                 assert oArgs.output, "--output required for this command" | ||||||
| 
 | 
 | ||||||
|         mark = b'\x00\x00\x00\x00\x1f\x1b\xed\x15' |  | ||||||
|         bOUT = mark |  | ||||||
|         # toxEsave |         # toxEsave | ||||||
|         assert bSAVE[:8] == bOUT, "Not a Tox profile" |         assert bSAVE[:8] == bMARK, "Not a Tox profile" | ||||||
|  |         bOUT = bMARK | ||||||
| 
 | 
 | ||||||
|         iErrs = 0 |         iErrs = 0 | ||||||
|         lOUT = []; aOUT = {} |         process_chunk(len(bOUT), bSAVE, oArgs) | ||||||
|         process_chunk(len(bOUT), bSAVE) |         if not bOUT: | ||||||
|         if aOUT: |             LOG.error(f"{oArgs.command} NO bOUT results") | ||||||
|             if oArgs.output: |         else: | ||||||
|                 oStream = open(oArgs.output, 'wb') |             oStream = None | ||||||
|             else: |             LOG.debug(f"command={oArgs.command} len bOUT={len(bOUT)} results") | ||||||
|                 oStream = sys.stdout |  | ||||||
| 
 | 
 | ||||||
|             if oArgs.command == 'save': |             if oArgs.command in ['edit'] or oArgs.info in ['save']: | ||||||
|                 oStream.write(bOUT) |                 LOG.debug(f"{oArgs.command} saving to {oArgs.output}") | ||||||
|  |                 oStream = open(oArgs.output, 'wb', encoding=None) | ||||||
|  |                 if oStream.write(bOUT) > 0: iRet = 0 | ||||||
|  |                 LOG.info(f"{oArgs.info}ed iRet={iRet} to {oArgs.output}") | ||||||
|             elif oArgs.info == 'info': |             elif oArgs.info == 'info': | ||||||
|                 pass |                 pass | ||||||
|             elif oArgs.info == 'yaml' and yaml: |             elif oArgs.info == 'yaml' and yaml: | ||||||
|  |                 LOG.debug(f"{oArgs.command} saving to {oArgs.output}") | ||||||
|  |                 oStream = open(oArgs.output, 'wt', encoding=sENC) | ||||||
|                 yaml.dump(aOUT, stream=oStream, indent=oArgs.indent) |                 yaml.dump(aOUT, stream=oStream, indent=oArgs.indent) | ||||||
|                 oStream.write('\n') |                 if oStream.write('\n') > 0: iRet = 0 | ||||||
|  |                 LOG.info(f"{oArgs.info}ing iRet={iRet} to {oArgs.output}") | ||||||
|             elif oArgs.info == 'json' and json: |             elif oArgs.info == 'json' and json: | ||||||
|  |                 LOG.debug(f"{oArgs.command} saving to {oArgs.output}") | ||||||
|  |                 oStream = open(oArgs.output, 'wb', encoding=None) | ||||||
|                 json.dump(aOUT, oStream, indent=oArgs.indent) |                 json.dump(aOUT, oStream, indent=oArgs.indent) | ||||||
|                 oStream.write('\n') |                 if oStream.write('\n') > 0: iRet = 0 | ||||||
|  |                 LOG.info(f"{oArgs.info}ing iRet={iRet} to {oArgs.output}") | ||||||
|             elif oArgs.info == 'repr': |             elif oArgs.info == 'repr': | ||||||
|                 oStream.write(repr(aOUT)) |                 LOG.debug(f"{oArgs.command} saving to {oArgs.output}") | ||||||
|                 oStream.write('\n') |                 oStream = open(oArgs.output, 'wt', encoding=sENC) | ||||||
|  |                 if oStream.write(repr(bOUT)) > 0: iRet = 0 | ||||||
|  |                 if oStream.write('\n') > 0: iRet = 0 | ||||||
|  |                 LOG.info(f"{oArgs.info}ing iRet={iRet} to {oArgs.output}") | ||||||
|             elif oArgs.info == 'pprint': |             elif oArgs.info == 'pprint': | ||||||
|  |                 LOG.debug(f"{oArgs.command} saving to {oArgs.output}") | ||||||
|  |                 oStream = open(oArgs.output, 'wt', encoding=sENC) | ||||||
|                 pprint(aOUT, stream=oStream, indent=oArgs.indent, width=80) |                 pprint(aOUT, stream=oStream, indent=oArgs.indent, width=80) | ||||||
|  |                 iRet = 0 | ||||||
|  |                 LOG.info(f"{oArgs.info}ing iRet={iRet} to {oArgs.output}") | ||||||
|             elif oArgs.info == 'nmap_tcp' and bHAVE_NMAP: |             elif oArgs.info == 'nmap_tcp' and bHAVE_NMAP: | ||||||
|                 assert oArgs.output, "--output required for this command" |                 assert oArgs.output, "--output required for this command" | ||||||
|                 oStream.close() |  | ||||||
|                 vOsSystemNmapTcp(aOUT["TCP_RELAY"], oArgs) |                 vOsSystemNmapTcp(aOUT["TCP_RELAY"], oArgs) | ||||||
|             elif oArgs.info == 'nmap_udp' and bHAVE_NMAP: |             elif oArgs.info == 'nmap_udp' and bHAVE_NMAP: | ||||||
|                 assert oArgs.output, "--output required for this command" |                 assert oArgs.output, "--output required for this command" | ||||||
|                 oStream.close() |  | ||||||
|                 vOsSystemNmapUdp(aOUT["DHT"], oArgs) |                 vOsSystemNmapUdp(aOUT["DHT"], oArgs) | ||||||
|             elif oArgs.info == 'nmap_onion' and bHAVE_NMAP: |             elif oArgs.info == 'nmap_onion' and bHAVE_NMAP: | ||||||
|                 assert oArgs.output, "--output required for this command" |                 assert oArgs.output, "--output required for this command" | ||||||
|                 oStream.close() |  | ||||||
|                 vOsSystemNmapUdp(aOUT["PATH_NODE"], oArgs) |                 vOsSystemNmapUdp(aOUT["PATH_NODE"], oArgs) | ||||||
| 
 | 
 | ||||||
|                                   |  | ||||||
|     if oStream and oStream != sys.stdout and oStream != sys.stderr: |     if oStream and oStream != sys.stdout and oStream != sys.stderr: | ||||||
|         oStream.close() |         oStream.close() | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 emdee
						emdee