pyui-desktop 0.5.0__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.
- pyui_desktop-0.5.0/PKG-INFO +91 -0
- pyui_desktop-0.5.0/PYUI/JS/connection.js +188 -0
- pyui_desktop-0.5.0/PYUI/JS/handler.js +336 -0
- pyui_desktop-0.5.0/PYUI/PYUICommonExecutable.spec +64 -0
- pyui_desktop-0.5.0/PYUI/Package/PYUI.py +590 -0
- pyui_desktop-0.5.0/PYUI/Package/bootstrap.py +702 -0
- pyui_desktop-0.5.0/PYUI/Package/pyuinode.py +33 -0
- pyui_desktop-0.5.0/PYUI/__pycache__/__init__.cpython-313.pyc +0 -0
- pyui_desktop-0.5.0/PYUI/__pycache__/buildscript.cpython-313.pyc +0 -0
- pyui_desktop-0.5.0/PYUI/__pycache__/buildtools.cpython-313.pyc +0 -0
- pyui_desktop-0.5.0/PYUI/__pycache__/compiler.cpython-313.pyc +0 -0
- pyui_desktop-0.5.0/PYUI/__pycache__/converter.cpython-313.pyc +0 -0
- pyui_desktop-0.5.0/PYUI/__pycache__/pyuinode.cpython-313.pyc +0 -0
- pyui_desktop-0.5.0/PYUI/__pycache__/settings.cpython-313.pyc +0 -0
- pyui_desktop-0.5.0/PYUI/__pycache__/tailwindBuilder.cpython-313.pyc +0 -0
- pyui_desktop-0.5.0/PYUI/boilerplate/index.css +2 -0
- pyui_desktop-0.5.0/PYUI/boilerplate/index.py +5 -0
- pyui_desktop-0.5.0/PYUI/boilerplate/index.xml +42 -0
- pyui_desktop-0.5.0/PYUI/buildscript.py +274 -0
- pyui_desktop-0.5.0/PYUI/buildtools.py +396 -0
- pyui_desktop-0.5.0/PYUI/compiler.py +463 -0
- pyui_desktop-0.5.0/PYUI/converter.py +149 -0
- pyui_desktop-0.5.0/PYUI/create.py +96 -0
- pyui_desktop-0.5.0/PYUI/dll/xmlParser.dll +0 -0
- pyui_desktop-0.5.0/PYUI/pyuinode.py +33 -0
- pyui_desktop-0.5.0/PYUI/requirements.txt +0 -0
- pyui_desktop-0.5.0/PYUI/settings.py +80 -0
- pyui_desktop-0.5.0/PYUI/tailwindBuilder.py +39 -0
- pyui_desktop-0.5.0/README.md +87 -0
- pyui_desktop-0.5.0/README_pypi.md +78 -0
- pyui_desktop-0.5.0/XMLParser/raw.c +658 -0
- pyui_desktop-0.5.0/XMLParser/xmlparser.c +640 -0
- pyui_desktop-0.5.0/pyproject.toml +31 -0
- pyui_desktop-0.5.0/pyui_desktop.egg-info/PKG-INFO +91 -0
- pyui_desktop-0.5.0/pyui_desktop.egg-info/SOURCES.txt +38 -0
- pyui_desktop-0.5.0/pyui_desktop.egg-info/dependency_links.txt +1 -0
- pyui_desktop-0.5.0/pyui_desktop.egg-info/requires.txt +5 -0
- pyui_desktop-0.5.0/pyui_desktop.egg-info/top_level.txt +3 -0
- pyui_desktop-0.5.0/setup.cfg +4 -0
- pyui_desktop-0.5.0/setup.py +4 -0
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: pyui-desktop
|
|
3
|
+
Version: 0.5.0
|
|
4
|
+
Summary: A short description of my package
|
|
5
|
+
Author-email: Akalabaya Pal <akalabaya.2008@proton.me>
|
|
6
|
+
Requires-Python: >=3.10
|
|
7
|
+
Description-Content-Type: text/markdown
|
|
8
|
+
Requires-Dist: pywebview==6.2.1
|
|
9
|
+
Requires-Dist: watchdog==6.0.0
|
|
10
|
+
Requires-Dist: websockets==16.0
|
|
11
|
+
Requires-Dist: colorama
|
|
12
|
+
Requires-Dist: pyinstaller
|
|
13
|
+
|
|
14
|
+
# PYUI(Python UI)
|
|
15
|
+
|
|
16
|
+
This project is targeted to make cross platform applications using python.PYUI is a layout pre-compiled framework for making python applications in very lightweight sizes. It uses a xml layouting system for defining layouts, python for logic and **PYWebview** as the renderer.Leading to a blank application size only 16MB compared to heavyweight rendering systems cosing 50+ MB or TKinter that has very legacy thread-unsafe architecture
|
|
17
|
+
|
|
18
|
+
## Motivation
|
|
19
|
+
1.**Making General Purpose Applications:** This project is driven by the motivation of making a framework over python that can be used to make general purpose applications with little or no learning curve.
|
|
20
|
+
|
|
21
|
+
2.**Smaller learning curve:** Recent solutions for UI development mostly are hard to learn and manage. However we adopted age-old xml layouting system that makes defining UI easy for anyone with little xml/html knowlege.
|
|
22
|
+
|
|
23
|
+
3.**Support of Python libaries and modules:** On the logic side python can use used to it's Limit, also the threadsafe nature of the framework helps in extreme scalability.
|
|
24
|
+
|
|
25
|
+
4.**Compiled Layout and Reusibility:** This framework has pre-compiled layouting system.So errors in layout are identified on runtime. Also Layout supports re-usibility using **PYUI Components**.
|
|
26
|
+
|
|
27
|
+
## Key Features of PYUI API
|
|
28
|
+
1. **DOM Manipulation:** One can change dom components from python side.There style,class,innertext and other attributes.
|
|
29
|
+
|
|
30
|
+
2. **PYUI Custom Syscalls:** Using this one can extend PYUI to support any JS libaries(chart.js and etc) by writing minimal Javascript.Or can use to commiunicate between JS ans Python runtime if needed without touching internal sockets.
|
|
31
|
+
|
|
32
|
+
3. **PYUI Hooks:** If some DOM updates are fast and can be lossy but realtime one can use PYUI Hooks.This can be mostly used to stream video or audio from Python to JS runtime
|
|
33
|
+
|
|
34
|
+
4. **Window Management:** A PYUI forms contain can contain more than one view(window) and **PYUI** provides apis to change windows dynamically. Also Exposes Webview object for *PYwebview* for changing the application window
|
|
35
|
+
|
|
36
|
+
5. **Forms Management:** **PYUI** provides dedicated apis to show and hide forms.
|
|
37
|
+
|
|
38
|
+
## Getting Started
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
### Setting up project
|
|
42
|
+
|
|
43
|
+
python -m PYUI.create <directory-of-project>
|
|
44
|
+
|
|
45
|
+
This will generate boilerplate project. Following folder and files will be generated in the given directory.
|
|
46
|
+
|
|
47
|
+
layout
|
|
48
|
+
code
|
|
49
|
+
layout/JS
|
|
50
|
+
layout/styles
|
|
51
|
+
code/index.py
|
|
52
|
+
code/__init__.py
|
|
53
|
+
layout/index.xml
|
|
54
|
+
settings.py
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
### Compiling project
|
|
58
|
+
|
|
59
|
+
To compile to a PYUI project and run it
|
|
60
|
+
|
|
61
|
+
python -m PYUI.buildtools --compile <directory-of-project> --run
|
|
62
|
+
|
|
63
|
+
This command will compile your project into a PYUI project and run it. Within few seconds(depending on project size) you can see you layout
|
|
64
|
+
|
|
65
|
+
To compile without running project
|
|
66
|
+
|
|
67
|
+
python -m PYUI.buildtools --compile <directory-of-project>
|
|
68
|
+
|
|
69
|
+
It will save your project in *build/temp_xxxxx.yyyy* (see last line of buildscript output). To launch the project go to the directory and run:
|
|
70
|
+
|
|
71
|
+
python bootstrap.py
|
|
72
|
+
|
|
73
|
+
It will launch your UI
|
|
74
|
+
|
|
75
|
+
### HotReloading Layouts
|
|
76
|
+
|
|
77
|
+
You can hot-reload the layout for faster UI development.
|
|
78
|
+
|
|
79
|
+
python -m PYUI.buildtools --hotreload <layout-xml-file>
|
|
80
|
+
|
|
81
|
+
Changing the xml file will reload the UI automatically
|
|
82
|
+
|
|
83
|
+
**Note:** Use the *--keepontop* flag to keep the UI on top always
|
|
84
|
+
|
|
85
|
+
For further API references for XML and PYUI check the documentation.
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
## Credits
|
|
89
|
+
|
|
90
|
+
PyWebview: https://github.com/r0x0r/pywebview
|
|
91
|
+
|
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
class PriorityQueue {
|
|
2
|
+
constructor(initialCapacity = 100) {
|
|
3
|
+
this.capacity = initialCapacity;
|
|
4
|
+
this.heap = new Array(this.capacity);
|
|
5
|
+
this.size = 0;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
// Insert a new object and check for resize
|
|
9
|
+
enqueue(priority, obj) {
|
|
10
|
+
// 1. Check if we need to resize before adding
|
|
11
|
+
if (this.size === this.capacity) {
|
|
12
|
+
this.resize();
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
// 2. Insert at the end of the heap
|
|
16
|
+
const newNode = { priority, object: obj };
|
|
17
|
+
this.heap[this.size] = newNode;
|
|
18
|
+
|
|
19
|
+
// 3. Heapify Up to restore min-heap property
|
|
20
|
+
this.heapifyUp(this.size);
|
|
21
|
+
this.size++;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
// Remove and return the highest priority item (lowest priority number)
|
|
25
|
+
dequeue() {
|
|
26
|
+
if (this.size === 0) return null;
|
|
27
|
+
|
|
28
|
+
const root = this.heap[0];
|
|
29
|
+
const lastNode = this.heap[this.size - 1];
|
|
30
|
+
|
|
31
|
+
// Move the last element to the root
|
|
32
|
+
this.heap[0] = lastNode;
|
|
33
|
+
this.heap[this.size - 1] = null; // Clear reference for garbage collection
|
|
34
|
+
this.size--;
|
|
35
|
+
|
|
36
|
+
// Heapify Down to restore min-heap property
|
|
37
|
+
if (this.size > 0) {
|
|
38
|
+
this.heapifyDown(0);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
return root;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// Double the array capacity when full
|
|
45
|
+
resize() {
|
|
46
|
+
this.capacity *= 2;
|
|
47
|
+
const newHeap = new Array(this.capacity);
|
|
48
|
+
|
|
49
|
+
// Copy elements over
|
|
50
|
+
for (let i = 0; i < this.size; i++) {
|
|
51
|
+
newHeap[i] = this.heap[i];
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
this.heap = newHeap;
|
|
55
|
+
console.log(`[PriorityQueue] Resized. New capacity: ${this.capacity}`);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// Restores heap order going up
|
|
59
|
+
heapifyUp(index) {
|
|
60
|
+
while (index > 0) {
|
|
61
|
+
const parentIndex = Math.floor((index - 1) / 2);
|
|
62
|
+
|
|
63
|
+
// If current node's priority is fine, break
|
|
64
|
+
if (this.heap[index].priority >= this.heap[parentIndex].priority) {
|
|
65
|
+
break;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
this.swap(index, parentIndex);
|
|
69
|
+
index = parentIndex;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// Restores heap order going down
|
|
74
|
+
heapifyDown(index) {
|
|
75
|
+
while (2 * index + 1 < this.size) {
|
|
76
|
+
let smallestChildIndex = 2 * index + 1; // Assume left child is smaller
|
|
77
|
+
const rightChildIndex = 2 * index + 2;
|
|
78
|
+
|
|
79
|
+
// Check if right child exists and has a lower priority number
|
|
80
|
+
if (
|
|
81
|
+
rightChildIndex < this.size &&
|
|
82
|
+
this.heap[rightChildIndex].priority < this.heap[smallestChildIndex].priority
|
|
83
|
+
) {
|
|
84
|
+
smallestChildIndex = rightChildIndex;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
// If parent is already smaller than the smallest child, we are done
|
|
88
|
+
if (this.heap[index].priority <= this.heap[smallestChildIndex].priority) {
|
|
89
|
+
break;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
this.swap(index, smallestChildIndex);
|
|
93
|
+
index = smallestChildIndex;
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
// Helper to swap two nodes in the array
|
|
98
|
+
swap(i, j) {
|
|
99
|
+
const temp = this.heap[i];
|
|
100
|
+
this.heap[i] = this.heap[j];
|
|
101
|
+
this.heap[j] = temp;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
peek() {
|
|
105
|
+
return this.size > 0 ? this.heap[0] : null;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
isEmpty() {
|
|
109
|
+
return this.size === 0;
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
var GLOBAL_SOCKET = null;
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
function connectSocket(port) {
|
|
123
|
+
|
|
124
|
+
socket = new WebSocket('ws://127.0.0.1:' + port.toString());
|
|
125
|
+
GLOBAL_SOCKET = socket;
|
|
126
|
+
const handler = new Msghandler(socket);
|
|
127
|
+
const priority_queue = new PriorityQueue(1000);
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
// 2. Triggered when the handshake successfully finishes
|
|
131
|
+
socket.onopen = (event) => {
|
|
132
|
+
console.log('Connected to Python WebSocket Server!');
|
|
133
|
+
};
|
|
134
|
+
|
|
135
|
+
// 3. Catch and parse incoming messages from Python as JSON objects
|
|
136
|
+
socket.onmessage = (event) => {
|
|
137
|
+
|
|
138
|
+
var data = JSON.parse(event.data);
|
|
139
|
+
if (data.type == "BATCH_UPDATE") {
|
|
140
|
+
handler.evaluateMsg(data);
|
|
141
|
+
}
|
|
142
|
+
else {
|
|
143
|
+
priority_queue.enqueue(data.count, data);
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
|
|
147
|
+
|
|
148
|
+
};
|
|
149
|
+
|
|
150
|
+
let nextExpectedSequence = 0;
|
|
151
|
+
//Run loop to dequeue the object and get the object
|
|
152
|
+
setInterval(() => {
|
|
153
|
+
|
|
154
|
+
while (!priority_queue.isEmpty()) {
|
|
155
|
+
const topItem = priority_queue.peek(); // Just look, don't remove yet!
|
|
156
|
+
|
|
157
|
+
// If the top item is exactly what we are waiting for, process it!
|
|
158
|
+
if (topItem.priority === nextExpectedSequence) {
|
|
159
|
+
const msg = priority_queue.dequeue();
|
|
160
|
+
|
|
161
|
+
handler.evaluateMsg(msg.object); // Run your UI framework logic here
|
|
162
|
+
|
|
163
|
+
nextExpectedSequence++; // Move to the next expected number
|
|
164
|
+
} else {
|
|
165
|
+
// The next message hasn't arrived from Python yet (there's a gap).
|
|
166
|
+
// Stop processing and wait for the network/socket to catch up!
|
|
167
|
+
break;
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
}, 16);
|
|
172
|
+
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
|
|
176
|
+
|
|
177
|
+
|
|
178
|
+
//Console log routing to main python console
|
|
179
|
+
console.log = function () {
|
|
180
|
+
// Convert arguments to a single string
|
|
181
|
+
var message = Array.from(arguments).join(' ');
|
|
182
|
+
|
|
183
|
+
// Send to Python API
|
|
184
|
+
if (window.pywebview && window.pywebview.api) {
|
|
185
|
+
window.pywebview.api.log(message);
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
};
|
|
@@ -0,0 +1,336 @@
|
|
|
1
|
+
var SECRET_KEY = null;
|
|
2
|
+
var GLOBAL_CUSTOM_SYSCALL_MAP = {}; // Js object to store all the custom syscalls
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
function register_sign(sign) {
|
|
6
|
+
SECRET_KEY = sign;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
async function standardSha256(message) {
|
|
10
|
+
// 1. Encode text string into an array of bytes (UTF-8)
|
|
11
|
+
const msgBuffer = new TextEncoder().encode(message);
|
|
12
|
+
|
|
13
|
+
// 2. Compute the raw SHA-256 hash buffer natively
|
|
14
|
+
const hashBuffer = await crypto.subtle.digest("SHA-256", msgBuffer);
|
|
15
|
+
|
|
16
|
+
// 3. Convert the raw binary array buffer into a hex string
|
|
17
|
+
const hashArray = Array.from(new Uint8Array(hashBuffer));
|
|
18
|
+
const hashHex = hashArray.map(b => b.toString(16).padStart(2, "0")).join("");
|
|
19
|
+
|
|
20
|
+
return hashHex;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
async function computeHmac(message, secretKey) {
|
|
25
|
+
const encoder = new TextEncoder();
|
|
26
|
+
|
|
27
|
+
// 1. Convert text inputs into byte arrays
|
|
28
|
+
const messageBytes = encoder.encode(message);
|
|
29
|
+
const keyBytes = encoder.encode(secretKey);
|
|
30
|
+
|
|
31
|
+
// 2. Import the raw secret key into the crypto engine
|
|
32
|
+
const cryptoKey = await crypto.subtle.importKey(
|
|
33
|
+
"raw",
|
|
34
|
+
keyBytes,
|
|
35
|
+
{ name: "HMAC", hash: "SHA-256" },
|
|
36
|
+
false,
|
|
37
|
+
["sign"]
|
|
38
|
+
);
|
|
39
|
+
|
|
40
|
+
// 3. Compute the raw binary signature
|
|
41
|
+
const signatureBuffer = await crypto.subtle.sign("HMAC", cryptoKey, messageBytes);
|
|
42
|
+
|
|
43
|
+
// 4. Convert the binary signature to a standard hexadecimal string
|
|
44
|
+
const hashArray = Array.from(new Uint8Array(signatureBuffer));
|
|
45
|
+
return hashArray.map(b => b.toString(16).padStart(2, "0")).join("");
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
async function _HandleCallbackSend(uuid, socket) {
|
|
50
|
+
//toSend = "{\"uuid\":\"" + uuid + "\",\"type\":\"CALLBACK\",\"data\":\"\"}";
|
|
51
|
+
toSend = { "uuid": uuid, "type": "CALLBACK", "data": "" };
|
|
52
|
+
|
|
53
|
+
send_str = JSON.stringify(toSend);
|
|
54
|
+
|
|
55
|
+
//Get the sha-256 encoded string.
|
|
56
|
+
sha256_encoded_msg = await standardSha256(send_str);
|
|
57
|
+
|
|
58
|
+
//make hmac
|
|
59
|
+
hmac_code = await computeHmac(sha256_encoded_msg, SECRET_KEY);
|
|
60
|
+
toSend['sign'] = hmac_code
|
|
61
|
+
|
|
62
|
+
socket.send(JSON.stringify(toSend)); //Send the msg back to python runtime
|
|
63
|
+
}
|
|
64
|
+
async function _HandleGrbContent(uuid, socket, value) {
|
|
65
|
+
|
|
66
|
+
toSend = { "uuid": uuid, "type": "GRAB_CONTENT", "data": value };
|
|
67
|
+
|
|
68
|
+
send_str = JSON.stringify(toSend);
|
|
69
|
+
|
|
70
|
+
//Get the sha-256 encoded string.
|
|
71
|
+
sha256_encoded_msg = await standardSha256(send_str);
|
|
72
|
+
|
|
73
|
+
//make hmac
|
|
74
|
+
hmac_code = await computeHmac(sha256_encoded_msg, SECRET_KEY);
|
|
75
|
+
toSend['sign'] = hmac_code
|
|
76
|
+
|
|
77
|
+
socket.send(JSON.stringify(toSend)); //Send the msg back to python runtime
|
|
78
|
+
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
function HandleStyleClass(args) {
|
|
83
|
+
//args: id,action and class
|
|
84
|
+
var id = args.id;
|
|
85
|
+
var action = args.action;
|
|
86
|
+
var cls = args.class;
|
|
87
|
+
|
|
88
|
+
var ele = document.getElementById(id);
|
|
89
|
+
|
|
90
|
+
if (ele) {
|
|
91
|
+
if (action == 'ADD') {
|
|
92
|
+
ele.classList.add(cls);
|
|
93
|
+
}
|
|
94
|
+
else if (action == 'REMOVE') {
|
|
95
|
+
ele.classList.remove(cls);
|
|
96
|
+
}
|
|
97
|
+
else if (action == 'TOGGLE') {
|
|
98
|
+
ele.classList.toggle(action);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
async function verifyIncomingMessage(incomingMsg) {
|
|
107
|
+
// 1. Extract the signature and remove it from the object we want to hash
|
|
108
|
+
const incomingSig = incomingMsg.sign;
|
|
109
|
+
delete incomingMsg.sign;
|
|
110
|
+
|
|
111
|
+
// 3. Sort keys and flatten (uuid is naturally included now!)
|
|
112
|
+
const sortedKeys = Object.keys(incomingMsg).sort();
|
|
113
|
+
let flatString = JSON.stringify(incomingMsg);
|
|
114
|
+
|
|
115
|
+
// 4. Hash, compare, and burn
|
|
116
|
+
const dataHash = await standardSha256(flatString);
|
|
117
|
+
const expectedSig = await computeHmac(dataHash, SECRET_KEY);
|
|
118
|
+
|
|
119
|
+
//console.log(flatString,dataHash);
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
if (incomingSig !== expectedSig) {
|
|
123
|
+
return false;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
return true;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
//Function for binding JS functions with Python syscall
|
|
131
|
+
async function bind(syscall, callback) {
|
|
132
|
+
|
|
133
|
+
//Assign the syscall to GLOBAL CUSTOM SYSCALL MAP
|
|
134
|
+
GLOBAL_CUSTOM_SYSCALL_MAP[syscall] = callback;
|
|
135
|
+
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
function generateUUID() {
|
|
139
|
+
return ([1e7]+-1e3+-4e3+-8e3+-1e11).replace(/[018]/g, c =>
|
|
140
|
+
(c ^ crypto.getRandomValues(new Uint8Array(1))[0] & 15 >> c / 4).toString(16)
|
|
141
|
+
);
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
async function sendSyscall(syscall, msg) {
|
|
145
|
+
var call = GLOBAL_CUSTOM_SYSCALL_MAP[syscall];
|
|
146
|
+
if (call) {
|
|
147
|
+
var toSend = { "data": msg, "type": syscall,"uuid":generateUUID() };
|
|
148
|
+
|
|
149
|
+
send_str = JSON.stringify(toSend);
|
|
150
|
+
|
|
151
|
+
//Get the sha-256 encoded string.
|
|
152
|
+
sha256_encoded_msg = await standardSha256(send_str);
|
|
153
|
+
|
|
154
|
+
//make hmac
|
|
155
|
+
hmac_code = await computeHmac(sha256_encoded_msg, SECRET_KEY);
|
|
156
|
+
toSend['sign'] = hmac_code
|
|
157
|
+
|
|
158
|
+
|
|
159
|
+
GLOBAL_SOCKET.send(JSON.stringify(toSend));
|
|
160
|
+
}
|
|
161
|
+
else {
|
|
162
|
+
console.log("Error:The callback " + syscall + " is not registered.");
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
|
|
167
|
+
class Msghandler {
|
|
168
|
+
constructor(socket) {
|
|
169
|
+
|
|
170
|
+
this.socket = socket;
|
|
171
|
+
this.callBackWrappers = new Object({});
|
|
172
|
+
this.processed_map = new Object({});
|
|
173
|
+
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
|
|
177
|
+
async evaluateMsg(jsonMessage) {
|
|
178
|
+
|
|
179
|
+
var type = jsonMessage.type;
|
|
180
|
+
var uuid = jsonMessage.uuid;
|
|
181
|
+
|
|
182
|
+
|
|
183
|
+
|
|
184
|
+
if (!(uuid in this.processed_map) && await verifyIncomingMessage(jsonMessage)) {
|
|
185
|
+
if (type == "EXECUTE_ONLY") {
|
|
186
|
+
|
|
187
|
+
//add it to processed list to maintain at most one call
|
|
188
|
+
this.processed_map[uuid] = true;
|
|
189
|
+
|
|
190
|
+
var content = jsonMessage.data;
|
|
191
|
+
this.handleExecuteJs(content);
|
|
192
|
+
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
else if (type == "REGISTER_CALLBACK") {
|
|
196
|
+
|
|
197
|
+
var id = jsonMessage.id;
|
|
198
|
+
var typeCallback = jsonMessage.callback_type;
|
|
199
|
+
var wrapper = this.registerCallback(id, typeCallback, uuid);
|
|
200
|
+
|
|
201
|
+
var container = { wrap: wrapper, type: typeCallback, Eleid: id };
|
|
202
|
+
console.log(container);
|
|
203
|
+
|
|
204
|
+
|
|
205
|
+
}
|
|
206
|
+
else if (type == "UNREGISTER_CALLBACK") {
|
|
207
|
+
var uuid_callback = jsonMessage.id;
|
|
208
|
+
cont = this.callBackWrappers[uuid_callback];
|
|
209
|
+
id = cont.Eleid;
|
|
210
|
+
type = cont.type;
|
|
211
|
+
wrap = cont.wrap;
|
|
212
|
+
document.getElementById(id).removeEventListener(type, wrap);
|
|
213
|
+
|
|
214
|
+
delete this.callBackWrappers[uuid_callback];
|
|
215
|
+
}
|
|
216
|
+
else if (type == "GRAB_CONTENT") {
|
|
217
|
+
var id = jsonMessage.id;
|
|
218
|
+
var attrib = jsonMessage.attrib;
|
|
219
|
+
|
|
220
|
+
if (attrib == 'value') {
|
|
221
|
+
var value = document.getElementById(id).value;
|
|
222
|
+
}
|
|
223
|
+
else if (attrib == 'text') {
|
|
224
|
+
var value = document.getElementById(id).textContent;
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
else {
|
|
228
|
+
var value = document.getElementById(id).getAttribute(attrib);
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
_HandleGrbContent(uuid, this.socket, value);
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
|
|
235
|
+
else if (type == "BATCH_UPDATE") {
|
|
236
|
+
|
|
237
|
+
//To update multiple things at once...
|
|
238
|
+
|
|
239
|
+
for (let index = 0; index < jsonMessage.batch.length; index++) {
|
|
240
|
+
this.evaluateMsg(jsonMessage.batch[index]);
|
|
241
|
+
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
|
|
246
|
+
else {
|
|
247
|
+
|
|
248
|
+
//Check if some custom syscall is present if present call it
|
|
249
|
+
|
|
250
|
+
var callback = GLOBAL_CUSTOM_SYSCALL_MAP[type];
|
|
251
|
+
if (callback) {
|
|
252
|
+
callback(jsonMessage);
|
|
253
|
+
}
|
|
254
|
+
else {
|
|
255
|
+
console.log("[Error] No associated callback for custom syscall:" + type);
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
}
|
|
260
|
+
else {
|
|
261
|
+
console.log("Wrong uuid or signature did not match.Hence dropping the packet.");
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
async handleExecuteJs(js_content) {
|
|
266
|
+
|
|
267
|
+
var execution_type = js_content.js_type;
|
|
268
|
+
var args = js_content.args;
|
|
269
|
+
|
|
270
|
+
if (execution_type == 'updateText') {
|
|
271
|
+
|
|
272
|
+
//We need text:value and id:id
|
|
273
|
+
var text = args.text;
|
|
274
|
+
var id = args.id;
|
|
275
|
+
|
|
276
|
+
//Update the text
|
|
277
|
+
var ele = document.getElementById(id);
|
|
278
|
+
|
|
279
|
+
if (ele) {
|
|
280
|
+
ele.textContent = text;
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
else if (execution_type == 'update') {
|
|
284
|
+
|
|
285
|
+
//We need value:value, id:id and att:attribute
|
|
286
|
+
var id = args.id;
|
|
287
|
+
var value = args.value;
|
|
288
|
+
var att = args.att;
|
|
289
|
+
|
|
290
|
+
var ele = document.getElementById(id);
|
|
291
|
+
|
|
292
|
+
if (ele) {
|
|
293
|
+
ele.setAttribute(att, value);
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
}
|
|
297
|
+
else if (execution_type == 'updateStyle') {
|
|
298
|
+
|
|
299
|
+
//We need id:id , att:attribute and value:value
|
|
300
|
+
var id = args.id;
|
|
301
|
+
var value = args.value;
|
|
302
|
+
var att = args.att;
|
|
303
|
+
|
|
304
|
+
|
|
305
|
+
|
|
306
|
+
var js = "document.getElementById(\"" + id + "\").style." + att + " = \"" + value + "\" ;"
|
|
307
|
+
eval(js);
|
|
308
|
+
}
|
|
309
|
+
else if (execution_type == 'addstyleclass') {
|
|
310
|
+
HandleStyleClass(args);
|
|
311
|
+
}
|
|
312
|
+
else if (execution_type == 'remove') {
|
|
313
|
+
|
|
314
|
+
var id = args.id;
|
|
315
|
+
var att = args.att;
|
|
316
|
+
var ele = document.getElementById(id);
|
|
317
|
+
ele.removeAttribute(att);
|
|
318
|
+
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
async registerCallback(id, eventType, uuid) {
|
|
323
|
+
|
|
324
|
+
//To handle the REGISTER_CALLBACK syscalls...
|
|
325
|
+
var element = document.getElementById(id);
|
|
326
|
+
var wrapper = () => _HandleCallbackSend(uuid, this.socket);
|
|
327
|
+
if (element) {
|
|
328
|
+
element.addEventListener(eventType, wrapper);
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
return wrapper;
|
|
332
|
+
|
|
333
|
+
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
# -*- mode: python ; coding: utf-8 -*-
|
|
2
|
+
|
|
3
|
+
import os
|
|
4
|
+
import glob
|
|
5
|
+
|
|
6
|
+
# 1. Name of well-defined folder
|
|
7
|
+
FOLDER_BUILD = os.environ.get('FOLDER')
|
|
8
|
+
FOLDET_OUT = os.environ.get('OUT')
|
|
9
|
+
PROJECT_NAME = os.environ.get('NAME')
|
|
10
|
+
IS_CONSOLE = os.environ.get('CONSOLE')
|
|
11
|
+
if IS_CONSOLE == '0':
|
|
12
|
+
IS_CONSOLE = False
|
|
13
|
+
else:
|
|
14
|
+
IS_CONSOLE = True
|
|
15
|
+
|
|
16
|
+
MODULE_FOLDER = 'code' # Change this to your folder's actual name
|
|
17
|
+
|
|
18
|
+
dynamic_modules = []
|
|
19
|
+
|
|
20
|
+
# 2. Automatically scan the folder for all Python files
|
|
21
|
+
search_path = os.path.join(MODULE_FOLDER, "**", "*.py")
|
|
22
|
+
for file_path in glob.glob(search_path, recursive=True):
|
|
23
|
+
if os.path.basename(file_path) != '__init__.py':
|
|
24
|
+
# Convert file path 'my_custom_folder/sub/module.py' -> 'my_custom_folder.sub.module'
|
|
25
|
+
module_name = os.path.splitext(file_path)[0].replace(os.sep, '.')
|
|
26
|
+
dynamic_modules.append(module_name)
|
|
27
|
+
|
|
28
|
+
#
|
|
29
|
+
|
|
30
|
+
a = Analysis(
|
|
31
|
+
['bootstrap.py'],
|
|
32
|
+
pathex=[],
|
|
33
|
+
binaries=[],
|
|
34
|
+
datas=[('code', 'code'), ('compiled_layouts', 'compiled_layouts'), ('layouts', 'layouts')],
|
|
35
|
+
hiddenimports=dynamic_modules,
|
|
36
|
+
hookspath=[],
|
|
37
|
+
hooksconfig={},
|
|
38
|
+
runtime_hooks=[],
|
|
39
|
+
excludes=[],
|
|
40
|
+
noarchive=False,
|
|
41
|
+
optimize=0,
|
|
42
|
+
)
|
|
43
|
+
pyz = PYZ(a.pure)
|
|
44
|
+
|
|
45
|
+
exe = EXE(
|
|
46
|
+
pyz,
|
|
47
|
+
a.scripts,
|
|
48
|
+
a.binaries,
|
|
49
|
+
a.datas,
|
|
50
|
+
[],
|
|
51
|
+
name=PROJECT_NAME,
|
|
52
|
+
debug=False,
|
|
53
|
+
bootloader_ignore_signals=False,
|
|
54
|
+
strip=False,
|
|
55
|
+
upx=True,
|
|
56
|
+
upx_exclude=[],
|
|
57
|
+
runtime_tmpdir=None,
|
|
58
|
+
console=IS_CONSOLE,
|
|
59
|
+
disable_windowed_traceback=False,
|
|
60
|
+
argv_emulation=False,
|
|
61
|
+
target_arch=None,
|
|
62
|
+
codesign_identity=None,
|
|
63
|
+
entitlements_file=None,
|
|
64
|
+
)
|