Skip to content

Commit 43340a4

Browse files
authored
Merge pull request #54 from Sathvik-Rao/release-2.0.0
Release 2.0.0
2 parents d6de80d + 98df6a9 commit 43340a4

File tree

73 files changed

+3697
-881
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

73 files changed

+3697
-881
lines changed
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
191 KB
Binary file not shown.
193 KB
Binary file not shown.
803 Bytes
Binary file not shown.

ClipCascade_Desktop/src/cli/login.py

+28-48
Original file line numberDiff line numberDiff line change
@@ -61,12 +61,8 @@ def mainloop(self):
6161
server_url.strip()
6262
)
6363

64-
websocket_url = (
65-
input(f"websocket url [{self.config.data['websocket_url']}]: ")
66-
or self.config.data["websocket_url"]
67-
)
68-
self.config.data["websocket_url"] = LoginForm.remove_trailing_slash(
69-
websocket_url.strip()
64+
self.config.data["websocket_url"] = Config.convert_to_websocket_url(
65+
self.config.data["server_url"]
7066
)
7167

7268
self.config.data["cipher_enabled"] = LoginForm.str_to_bool(
@@ -89,48 +85,6 @@ def mainloop(self):
8985
CustomDialog("Logging in...").mainloop()
9086
return
9187

92-
subscription_destination = (
93-
input(
94-
f"subscription destination [{self.config.data['subscription_destination']}]: "
95-
)
96-
or self.config.data["subscription_destination"]
97-
)
98-
self.config.data["subscription_destination"] = LoginForm.remove_trailing_slash(
99-
subscription_destination.strip()
100-
)
101-
102-
send_destination = (
103-
input(f"send destination [{self.config.data['send_destination']}]: ")
104-
or self.config.data["send_destination"]
105-
)
106-
self.config.data["send_destination"] = LoginForm.remove_trailing_slash(
107-
send_destination.strip()
108-
)
109-
110-
login_url = (
111-
input(f"login url [{self.config.data['login_url']}]: ")
112-
or self.config.data["login_url"]
113-
)
114-
self.config.data["login_url"] = LoginForm.remove_trailing_slash(
115-
login_url.strip()
116-
)
117-
118-
logout_url = (
119-
input(f"logout url [{self.config.data['logout_url']}]: ")
120-
or self.config.data["logout_url"]
121-
)
122-
self.config.data["logout_url"] = LoginForm.remove_trailing_slash(
123-
logout_url.strip()
124-
)
125-
126-
maxsize_url = (
127-
input(f"maxsize url [{self.config.data['maxsize_url']}]: ")
128-
or self.config.data["maxsize_url"]
129-
)
130-
self.config.data["maxsize_url"] = LoginForm.remove_trailing_slash(
131-
maxsize_url.strip()
132-
)
133-
13488
# Validate hash_rounds
13589
while True:
13690
hash_rounds = input(
@@ -210,6 +164,32 @@ def mainloop(self):
210164
or LoginForm.bool_to_str(self.config.data["enable_file_sharing"])
211165
)
212166

167+
# Validate default file download location
168+
while True:
169+
default_file_download_location = (
170+
input(
171+
f"default file download location [{self.config.data['default_file_download_location']}]: "
172+
)
173+
or self.config.data["default_file_download_location"]
174+
)
175+
176+
default_file_download_location = default_file_download_location.strip()
177+
if default_file_download_location == "":
178+
self.config.data["default_file_download_location"] = ""
179+
break
180+
181+
if not os.path.isdir(default_file_download_location):
182+
CustomDialog(
183+
"Invalid directory path.",
184+
msg_type="error",
185+
).mainloop()
186+
continue
187+
188+
self.config.data["default_file_download_location"] = (
189+
default_file_download_location
190+
)
191+
break
192+
213193
CustomDialog("Logging in...").mainloop()
214194

215195
def on_quit(self):

ClipCascade_Desktop/src/cli/tray.py

+12-6
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77

88
from cli.echo import Echo
99
from cli.info import CustomDialog
10+
from core.config import Config
1011
from core.constants import *
1112
from itertools import count
1213

@@ -18,19 +19,21 @@
1819
class TaskbarPanel:
1920
def __init__(
2021
self,
21-
on_connect_callback=None,
22-
on_disconnect_callback=None,
23-
on_logoff_callback=None,
24-
new_version_available=None,
25-
github_url=None,
22+
on_connect_callback: callable = None,
23+
on_disconnect_callback: callable = None,
24+
on_logoff_callback: callable = None,
25+
new_version_available: list = None,
26+
github_url: str = GITHUB_URL,
2627
stomp_manager=None,
28+
config: Config = None,
2729
):
2830
self.on_connect_callback = on_connect_callback
2931
self.on_disconnect_callback = on_disconnect_callback
3032
self.on_logoff_callback = on_logoff_callback
3133
self.new_version_available = new_version_available
3234
self.github_url = github_url
3335
self.stomp_manager = stomp_manager
36+
self.config = config
3437

3538
# Initial state: Connected
3639
self.is_connected = True
@@ -254,7 +257,10 @@ def disable_files_download(self):
254257

255258
def _on_download(self, files):
256259
try:
257-
target_directory = input("Enter the location to save file(s): ").strip()
260+
if self.config.data["default_file_download_location"] != "":
261+
target_directory = self.config.data["default_file_download_location"]
262+
else:
263+
target_directory = input("Enter the location to save file(s): ").strip()
258264
if not target_directory:
259265
CustomDialog(
260266
"No input provided. Please enter a valid directory path.",

ClipCascade_Desktop/src/clipboard/clipboard_monitor_linux.py

+8-13
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ def _monitor_x_wl_clipboard(
6767
if x_mode:
6868
timeout = 0.3 # xclip seconds
6969
else:
70-
timeout = 5 # wl-clipboard seconds
70+
timeout = 1 # wl-clipboard seconds
7171

7272
while _run_poll.is_set():
7373
if x_mode:
@@ -226,23 +226,18 @@ def execute_command(*args) -> tuple:
226226

227227
def is_x_clipboard_owner():
228228
# Check if the X clipboard is owned by the current user
229-
success, msg = execute_command(
230-
"xclip", "-selection", "clipboard", "-t", "TARGETS", "-o"
231-
)
232-
if not success:
233-
if msg.lower().find("there is no owner for the clipboard selection") != -1:
234-
logging.warning(
235-
f"{msg}\nX clipboard is not owned by the current user switching to wl-clipboard."
236-
)
237-
return False
238-
239-
return True
229+
return execute_command("xclip", "-selection", "clipboard", "-t", "TARGETS", "-o")[0]
240230

241231

242232
def _start_clipboard_polling(enable_image_monitoring, enable_file_monitoring):
243233
if XMODE:
234+
x_clipboard_owner = is_x_clipboard_owner()
235+
if not x_clipboard_owner:
236+
logging.warning(
237+
"x-clip is not owned by the current user. Switching to wl-clipboard."
238+
)
244239
_monitor_x_wl_clipboard(
245-
x_mode=is_x_clipboard_owner(),
240+
x_mode=x_clipboard_owner,
246241
enable_image_monitoring=enable_image_monitoring,
247242
enable_file_monitoring=enable_file_monitoring,
248243
)

ClipCascade_Desktop/src/core/application.py

+10-1
Original file line numberDiff line numberDiff line change
@@ -137,10 +137,11 @@ def authenticate_and_connect(self):
137137
and self.config.data["save_password"]
138138
and not used_saved_credentials
139139
):
140-
# Attempt to connect with raw password when using saved credentials
140+
# Attempt to connect with password when using saved credentials
141141
used_saved_credentials = True
142142
else:
143143
display_login_success_dialog = True
144+
self.config.data["password"] = "" # Clear the password
144145
login_form = LoginForm(
145146
self.config,
146147
on_quit_callback=(
@@ -150,11 +151,17 @@ def authenticate_and_connect(self):
150151
),
151152
)
152153
login_form.mainloop() # wait until login form is closed
154+
self.config.data["password"] = (
155+
CipherManager.string_to_sha3_512_lowercase_hex(
156+
self.config.data["password"]
157+
)
158+
) # Hash the password
153159

154160
login_successful, msg_login, self.config.data["cookie"] = (
155161
self.request_manager.login()
156162
)
157163
if login_successful:
164+
self.config.data["csrf_token"] = self.request_manager.get_csrf_token()
158165
self.config.data["maxsize"] = self.request_manager.maxsize()
159166
stomp_conn_successful, msg_stomp = self.stomp_manager.connect()
160167
if stomp_conn_successful:
@@ -219,6 +226,7 @@ def logoff_and_exit(self):
219226
self.config.data["cookie"] = None
220227
self.config.data["maxsize"] = None
221228
self.config.data["password"] = ""
229+
self.config.data["csrf_token"] = ""
222230
self.config.save()
223231
except Exception as e:
224232
raise Exception(f"Error during logging off: {e}")
@@ -248,6 +256,7 @@ def run(self):
248256
new_version_available=update_available,
249257
github_url=GITHUB_URL,
250258
stomp_manager=self.stomp_manager,
259+
config=self.config,
251260
)
252261
self.stomp_manager.set_tray_ref(sys_tray)
253262
sys_tray.run()

ClipCascade_Desktop/src/core/config.py

+26-6
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import base64
22
import json
33
import os
4+
import re
45
from core.constants import *
56

67

@@ -10,24 +11,21 @@ def __init__(self, file_name=DATA_FILE_NAME):
1011
self.data = {
1112
"cipher_enabled": True,
1213
"server_url": "http://localhost:8080",
13-
"websocket_url": "ws://localhost:8080/clipsocket",
14+
"websocket_url": "",
1415
"username": "",
1516
"hashed_password": None,
1617
"cookie": None,
1718
"maxsize": None,
18-
"subscription_destination": "/topic/cliptext",
19-
"send_destination": "/app/cliptext",
2019
"hash_rounds": 664937,
21-
"login_url": "/login",
22-
"logout_url": "/logout",
23-
"maxsize_url": "/max-size",
2420
"salt": "",
21+
"csrf_token": "",
2522
"notification": True,
2623
"save_password": False,
2724
"password": "",
2825
"max_clipboard_size_local_limit_bytes": None,
2926
"enable_image_sharing": True,
3027
"enable_file_sharing": True,
28+
"default_file_download_location": "",
3129
}
3230

3331
def save(self):
@@ -66,3 +64,25 @@ def load(self):
6664
"Try deleting DATA file in the program directory, and re-run the program again"
6765
)
6866
return False
67+
68+
@staticmethod
69+
def convert_to_websocket_url(input_url):
70+
if not input_url or not isinstance(input_url, str):
71+
raise ValueError("Invalid URL provided")
72+
73+
# Trim whitespace, remove trailing slashes, and convert to lowercase
74+
input_url = re.sub(r"/+$", "", input_url.strip()).lower()
75+
76+
# Determine protocol and convert
77+
if input_url.startswith("https://"):
78+
ws_url = input_url.replace("https://", "wss://", 1)
79+
elif input_url.startswith("http://"):
80+
ws_url = input_url.replace("http://", "ws://", 1)
81+
else:
82+
raise ValueError(f"Unsupported protocol in URL: {input_url}")
83+
84+
# Append the WebSocket endpoint and remove any trailing slash
85+
ws_url += WEBSOCKET_ENDPOINT
86+
ws_url = re.sub(r"/+$", "", ws_url)
87+
88+
return ws_url

ClipCascade_Desktop/src/core/constants.py

+12-4
Original file line numberDiff line numberDiff line change
@@ -70,14 +70,14 @@ def detect_linux_display_server():
7070

7171
# App version
7272
if PLATFORM == WINDOWS:
73-
APP_VERSION = "1.3.0"
73+
APP_VERSION = "2.0.0"
7474
elif PLATFORM == MACOS:
75-
APP_VERSION = "1.3.1"
75+
APP_VERSION = "2.0.0"
7676
elif PLATFORM.startswith(LINUX):
7777
if XMODE:
78-
APP_VERSION = "1.3.2" # gui version
78+
APP_VERSION = "2.0.0" # gui version
7979
else:
80-
APP_VERSION = "1.3.2" # non-gui(cli) version
80+
APP_VERSION = "2.0.0" # non-gui(cli) version
8181

8282

8383
# core constants
@@ -87,6 +87,14 @@ def detect_linux_display_server():
8787
LOG_LEVEL = logging.INFO # Use valid levels: DEBUG, INFO, WARNING, ERROR, CRITICAL
8888
DATA_FILE_NAME = "DATA"
8989
MAX_SIZE = 1048576 # 1 MiB
90+
SUBSCRIPTION_DESTINATION = "/user/queue/cliptext"
91+
SEND_DESTINATION = "/app/cliptext"
92+
LOGIN_URL = "/login"
93+
LOGOUT_URL = "/logout"
94+
MAXSIZE_URL = "/max-size"
95+
CSRF_URL = "/csrf-token"
96+
WEBSOCKET_ENDPOINT = "/clipsocket"
97+
9098
VERSION_URL = (
9199
"https://raw.githubusercontent.com/Sathvik-Rao/ClipCascade/main/version.json"
92100
)

0 commit comments

Comments
 (0)