fzx2 1.0.0__py3-none-any.whl

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,82 @@
1
+ Metadata-Version: 2.4
2
+ Name: fzx2
3
+ Version: 1.0.0
4
+ Summary: 507EX executable format version 2.0
5
+ Author-email: Wyatt Brashear <admin@wyattb.dev>
6
+ License: MIT
7
+ Requires-Python: >=3.10
8
+ Requires-Dist: flask~=3.1.2
9
+ Requires-Dist: requests>=2.32.5
10
+ Description-Content-Type: text/markdown
11
+
12
+ # 507ex 2.0 (FZX2)
13
+ ## What is 507ex, and why is there a 2.0?
14
+ A while back, I created a executable format called 507ex (507 Being my brand that I like to put things under). I made one
15
+ mistake on the first time. I used AI in my code. That completely ruined my code. So I decided it was time to rewrite it.
16
+ Introducing 507ex 2.0 (Abbreviated as FZX2).
17
+ ### What's New?
18
+ - AI was not used to write code (yay)
19
+ - Enhanced metadata that stores more information
20
+ - Auto Dependency Manager. Uses a list embedded in the metadata to ensure the application has the correct dependencies.
21
+ - All operations are accessible through one module.
22
+ - CAR (Central Application Repository) now supports authentication.
23
+ ## CAR (Central Application Repository)
24
+ CAR is a server system that allows seamless execution of applications from the command line.
25
+ Example:
26
+ ~~~bash
27
+ python3 fzx2.py exec http://127.0.0.1:5000/pull/955d7c5f-5b21-428f-94e4-8e13f1e7223c
28
+ ~~~
29
+ Easy as that! All CAR operations are authenticated by a random "secret code" generated by the server.
30
+ ### Endpoint Documentation
31
+ POST: /push. Push an executable to the server. Accepts form data in the following form: {'file_id': STR}, and accepts file data in this form: {'file': FILE}.
32
+ Returns:
33
+ ```json
34
+ {
35
+ "status": "success",
36
+ "secret_code": "secret_code",
37
+ "url": "request.url_root/pull/filename"
38
+ }
39
+ ```
40
+ POST: /pull/<file_id>. Pull an executable from the server. Accepts form data in the following form: {'secret_code': STR}
41
+ Returns:
42
+ The file requested or an error message. Files are sent using flask's send_from_directory function.
43
+ ### Running the server
44
+ Source Code Method:
45
+ ~~~bash
46
+ python3 fzx2.py start_server
47
+ ~~~
48
+ Compiled Executable Method:
49
+ ~~~bash
50
+ ./fzx2 start_server
51
+ ~~~
52
+ ## Installation
53
+ ### Method 1 (Compiled Executable)
54
+ 1. Download the latest release from the releases page.
55
+ 2. Run the executable. (Recommended to be done in a terminal)
56
+ ### Method 2 (Source Code)
57
+ 1. Clone the Repository using `git clone https://github.com/WyattBrashear/507ex-utils2.git`
58
+ 2. Run: `pip install -r requirements.txt` in order to install the dependencies.
59
+ 3. Run the main script using `python3 fzx2.py`
60
+ ## CLI Usage
61
+ `python3 fzx2.py <operation> <path>`
62
+ All operations are listed below:
63
+ 1. exec: Executes an executable
64
+ 2. start_server: Starts the CAR server
65
+ 3. build: Builds an executable
66
+ 4. unpack: Unpacks an executable
67
+ 5. upload: Uploads an executable
68
+ ## 507ex's required files
69
+ All directories that are going to be turned into a 507ex requires 2 files:
70
+ 1. runfile (contains the command to run the script)
71
+ 2. dependfile
72
+ Dependfile is in this format
73
+ ~~~text
74
+ !{name}|{command}
75
+ !PLATFORM {platform}
76
+ {dependencies}
77
+ ~~~
78
+ ## Demo Video
79
+ https://drive.google.com/file/d/1QfDZL2Spc7WKqbfCU_m7xSnRLbJdnfNd/view?usp=sharing
80
+ ## AI Usage
81
+ As per usual, I am against using AI in my code. All the code in this repository was human written. The instances of AI
82
+ usage was autocomplete and AI Assistant when I was stuck, pointing me in the right direction (fzx2.py).
@@ -0,0 +1,5 @@
1
+ script/fzx2.py,sha256=3tTazvcqDiRoAEGaX7Aml72m5xUMUSYVT2t1C449luY,8217
2
+ fzx2-1.0.0.dist-info/METADATA,sha256=NzalqP7Atu3gdTn_B10JwQ0_DOWnhXNYd8-KvAh_3ak,3251
3
+ fzx2-1.0.0.dist-info/WHEEL,sha256=QccIxa26bgl1E6uMy58deGWi-0aeIkkangHcxk2kWfw,87
4
+ fzx2-1.0.0.dist-info/entry_points.txt,sha256=E891uRz1tI50-cK3XnuBs2lQBBps07GsNomHnMW-O1o,42
5
+ fzx2-1.0.0.dist-info/RECORD,,
@@ -0,0 +1,4 @@
1
+ Wheel-Version: 1.0
2
+ Generator: hatchling 1.29.0
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
@@ -0,0 +1,2 @@
1
+ [console_scripts]
2
+ fzx2 = script.fzx2:main
script/fzx2.py ADDED
@@ -0,0 +1,208 @@
1
+ import argparse
2
+ import hashlib
3
+ import json
4
+ import os
5
+ import random
6
+ import shutil
7
+ import subprocess
8
+ import sys
9
+ import uuid
10
+ import zipfile
11
+ from datetime import datetime
12
+
13
+ import requests
14
+ from flask import Flask, request, send_from_directory
15
+ from werkzeug.utils import secure_filename
16
+
17
+
18
+ app = Flask(__name__)
19
+ @app.route('/push', methods=['POST'])
20
+ def push():
21
+ print(os.getcwd())
22
+ filename = secure_filename(request.form.get('file_id'))
23
+ with open(os.path.join("storage", f"{filename}.507ex"), 'wb') as f:
24
+ f.write(request.files['file'].read())
25
+ with open(os.path.join("storage", f"{filename}.json"), 'w') as f:
26
+ secret_code = random.randint(100000, 999999)
27
+ data = {
28
+ 'secret_code': hashlib.sha256(str(secret_code).encode()).hexdigest(),
29
+ }
30
+ json.dump(data, f)
31
+ return {
32
+ 'status': 'success',
33
+ 'secret_code': str(secret_code),
34
+ 'url': f'{request.url_root}pull/{filename}'
35
+ }
36
+
37
+ @app.route('/pull/<file_id>', methods=['POST'])
38
+ def pull(file_id):
39
+ try:
40
+ with open(os.path.join("storage", f"{file_id}.json"), 'r') as json_file:
41
+ codefile = json.load(json_file)
42
+ secret_code = codefile['secret_code']
43
+ except FileNotFoundError:
44
+ return 'File not found', 404
45
+ if request.form.get('secret_code') == secret_code:
46
+ return send_from_directory('storage', f"{file_id}.507ex", as_attachment=True)
47
+ else:
48
+ return 'Invalid secret code', 401
49
+ #Alright. Lets rewrite this format!
50
+ def build(directory: str):
51
+ #Check for a runfile in the directory
52
+ if not os.path.exists(os.path.join(directory, 'runfile')):
53
+ raise FileNotFoundError('No Runfile Detected!')
54
+ depend_file = False
55
+ if os.path.exists(os.path.join(directory, 'dependfile')):
56
+ depend_file = True
57
+ with open(os.path.join(directory, 'dependfile'), 'r') as f:
58
+ dependencies = f.read()
59
+ shutil.make_archive(directory, 'zip', directory)
60
+ os.rename(f"{directory}.zip", os.path.join(f"{directory}.507ex"))
61
+ with open (os.path.join(f"{directory}.507ex"), 'rb') as f:
62
+ exec_contents = f.read()
63
+ #Calculate hash
64
+ hashfunc = hashlib.new('blake2s')
65
+ with open(os.path.join(f"{directory}.507ex"), 'rb') as f:
66
+ while chunk := f.read(8192):
67
+ hashfunc.update(chunk)
68
+ exec_hash = hashfunc.hexdigest()
69
+
70
+ with open(os.path.join(f"{directory}.507ex"), 'wb') as f:
71
+ f.write("FZX2".encode())
72
+ f.write("\n!507EX-METADATA".encode())
73
+ f.write(f"\n507ex-hash|{exec_hash}".encode())
74
+ f.write(f"\n507ex-hashmode|blake2s".encode())
75
+ f.write(f"\n507ex-id|{uuid.uuid4()}".encode())
76
+ #DTOC - Date/Time of Creation
77
+ f.write(f"\n507ex-dtoc|{datetime.now().now()}".encode())
78
+ f.write(f"\n507ex-depends|{depend_file}".encode())
79
+ f.write(f"\n!507EX-DEPENDENCIES\n{dependencies}".encode())
80
+ f.write("\n!507EX-END-META\n".encode())
81
+ f.write(exec_contents)
82
+ print(f"Successfully built {directory}.507ex")
83
+
84
+ def execute(path: str):
85
+ print(path)
86
+ current_path = os.getcwd()
87
+ reading_depends = False
88
+ has_depends = False
89
+ dependency_platform = ''
90
+ fromcar = False
91
+ #CAR Server logic
92
+ if path.startswith("http://") or path.startswith("https://"):
93
+ r = requests.post(path, data={'secret_code': hashlib.sha256(str(input("Please enter the secret code: \n")).encode()).hexdigest()})
94
+ if r.status_code == 401:
95
+ print("Your Secret Code is invalid!")
96
+ with open("tmp.507ex", 'wb') as f:
97
+ f.write(r.content)
98
+ fromcar = True
99
+ path = "tmp.507ex"
100
+ with open(path, 'rb') as f:
101
+ if f.readline() != b'FZX2\n':
102
+ raise ValueError('Invalid Executable!')
103
+ line_counter = 0
104
+ for line in f:
105
+ if line.startswith(b'!507EX-END-META'):
106
+ break
107
+ if line.startswith(b'507ex-hash|'):
108
+ exec_hash = line.split(b'|')[1].decode().replace('\n', '')
109
+ if line.startswith(b'507ex-hashmode'):
110
+ exec_hashmode = line.split(b'|')[1].decode().replace('\n', '')
111
+ if line.startswith(b'507ex-id'):
112
+ exec_id = line.split(b'|')[1].decode().replace('\n', '')
113
+ if line.startswith(b'507ex-depends'):
114
+ if line.split(b'|')[1].decode() == 'True\n':
115
+ if input("Executable has dependencies that it wants to install. Continue? (y/n)\n").lower() == 'y':
116
+ has_depends = True
117
+ else:
118
+ raise ValueError('Aborted!')
119
+ else:
120
+ has_depends = False
121
+ if reading_depends:
122
+ if line.startswith(b'!') and not line.startswith(b'!PLATFORM'):
123
+ command = line.split(b'|')[1].decode().replace('\n', '')
124
+ if dependency_platform == sys.platform or dependency_platform == '*':
125
+ arg = line.decode().replace('\n', '')
126
+ subprocess.run(f"{command} {arg}", shell=True, check=False)
127
+ if line.startswith(b'!PLATFORM'):
128
+ dependency_platform = line.decode().replace('\n', '').replace('!PLATFORM ', '')
129
+ if line.startswith(b'!507EX-DEPENDENCIES'):
130
+ if has_depends:
131
+ reading_depends = True
132
+ line_counter += 1
133
+ os.makedirs(os.path.join(current_path, '.fzx2-runtime', exec_id), exist_ok=True)
134
+ #Hash the executable
135
+ line_counter +=2
136
+ with open(path, 'rb') as f:
137
+ lines = b''.join(f.readlines()[line_counter:])
138
+ file_hash = hashlib.new(exec_hashmode, lines).hexdigest()
139
+ pass_hashcheck = False
140
+ if file_hash == exec_hash:
141
+ pass_hashcheck = True
142
+ else:
143
+ raise ValueError('Hash Verification Failed. Executable may have been damaged.')
144
+ os.chdir(os.path.join(current_path, '.fzx2-runtime', exec_id))
145
+ with zipfile.ZipFile(os.path.join(current_path, path), 'r') as zippy:
146
+ zippy.extractall()
147
+ with open("runfile", 'r') as runfile:
148
+ runfile_contents = runfile.read()
149
+ try:
150
+ subprocess.run(runfile_contents, shell=True, check=False)
151
+ except:
152
+ print("Exiting 507ex enviornment...")
153
+ #cleanup
154
+ os.chdir('..')
155
+ shutil.rmtree(os.path.join(current_path, '.fzx2-runtime', exec_id))
156
+ if fromcar:
157
+ os.remove(os.path.join(current_path, "tmp.507ex"))
158
+
159
+ def upload(path: str):
160
+ if not os.path.exists(path):
161
+ raise FileNotFoundError('File not found!')
162
+ url = input("Please enter the server address: \n")
163
+ with open(path, 'rb') as f:
164
+ for line in f:
165
+ if line.startswith(b'507ex-id|'):
166
+ exec_id = line.split(b'|')[1].decode()
167
+ break
168
+ with open(path, 'rb') as f:
169
+ r = requests.post(f"{url}/push", files={'file': f}, data={'file_id': exec_id})
170
+ json_data = r.json()
171
+ print('Upload Complete!')
172
+ print(f"Upload URL: {json_data['url']}")
173
+ print(f"Your Secret Code Is: {json_data['secret_code']}")
174
+ def unpack(path: str):
175
+ os.mkdir(path)
176
+ os.chdir(path)
177
+ with zipfile.ZipFile(path, 'r') as zippy:
178
+ zippy.extractall()
179
+
180
+ def main():
181
+ parser = argparse.ArgumentParser()
182
+ parser.add_argument('mode', choices=['build', 'upload', 'exec', 'unpack', 'start_server'],
183
+ help='The operation to perform.')
184
+ parser.add_argument('path', help='The path to the Executable or folder')
185
+ args = parser.parse_args(sys.argv[1:])
186
+ if args.mode == 'build':
187
+ build(args.path)
188
+ if args.mode == 'exec':
189
+ try:
190
+ execute(args.path)
191
+ except KeyboardInterrupt:
192
+ print("Exiting 507ex enviornment...")
193
+ if os.path.exists("tmp.507ex"):
194
+ os.remove(f"tmp.507ex")
195
+ except Exception as e:
196
+ print(f"An error occured while executing the executable: {e}")
197
+ if args.mode == 'upload':
198
+ upload(args.path)
199
+ if args.mode == 'unpack':
200
+ unpack(args.path)
201
+ if args.mode == 'start_server':
202
+ try:
203
+ os.mkdir(os.path.join('.', 'storage'))
204
+ except FileExistsError:
205
+ pass
206
+ app.run()
207
+ if __name__ == '__main__':
208
+ main()