diff --git a/bin/post-commit b/bin/post-commit
index 8e8e7da7..88f309f4 100755
--- a/bin/post-commit
+++ b/bin/post-commit
@@ -5,11 +5,15 @@ set -e
URL=https://fman.io/api/record-commit/
+if [ -z "${FMAN_API_SECRET:-}" ]; then
+ exit 0
+fi
+
message_tmp_file=`mktemp`
git log --pretty=format:%B -n1 > ${message_tmp_file}
sha=`git log --pretty=format:%H -n1`
date=`git log --pretty=format:%cd --date=iso-strict -n1`
-curl --data-urlencode secret=k92XhhhmOf8rD7QJ --data-urlencode sha=${sha} \
+curl --fail --silent --data-urlencode secret=${FMAN_API_SECRET} --data-urlencode sha=${sha} \
--data-urlencode date=${date} --data-urlencode message@${message_tmp_file} \
${URL}
rm ${message_tmp_file}
\ No newline at end of file
diff --git a/build.py b/build.py
index 60255c1a..f9988e72 100644
--- a/build.py
+++ b/build.py
@@ -96,7 +96,7 @@ def release():
settings_path, next_version + snapshot_suffix,
'Bump version for next development iteration'
)
- git('push', '-u', 'origin', 'master')
+ git('push', '-u', 'origin', 'main')
try:
git('push', 'origin', release_tag)
try:
@@ -106,7 +106,7 @@ def release():
' git pull\n'
' git checkout %s\n'
' python build.py release\n'
- ' git checkout master\n\n'
+ ' git checkout main\n\n'
'on the other OSs now, then come back here and do:'
'\n\n'
' python build.py post_release\n'
@@ -117,7 +117,7 @@ def release():
raise
except:
git('revert', '--no-edit', revision_before + '..HEAD' )
- git('push', '-u', 'origin', 'master')
+ git('push', '-u', 'origin', 'main')
revision_before = git('rev-parse', 'HEAD').rstrip()
raise
except:
@@ -149,7 +149,7 @@ def post_release():
create_cloudfront_invalidation(cloudfront_items_to_invalidate)
record_release_on_server()
upload_core_to_github()
- git('checkout', 'master')
+ git('checkout', 'main')
def _prompt_for_next_version(release_version):
next_version = _get_suggested_next_version(release_version)
diff --git a/requirements/base.txt b/requirements/base.txt
index a2bddc2e..513111af 100644
--- a/requirements/base.txt
+++ b/requirements/base.txt
@@ -1,4 +1,4 @@
-fbs[sentry] @ http://build-system.fman.io/pro/b5aab865-bd29-4f23-992c-0eb4f3a24f33/0.9.4
+fbs[sentry] @ https://build-system.fman.io/pro/b5aab865-bd29-4f23-992c-0eb4f3a24f33/0.9.4
PyQt5==5.15.11
PyInstaller==6.19.0
rsa==4.9
diff --git a/src/build/python/build_impl/__init__.py b/src/build/python/build_impl/__init__.py
index 086f20aa..5b58965f 100644
--- a/src/build/python/build_impl/__init__.py
+++ b/src/build/python/build_impl/__init__.py
@@ -105,7 +105,7 @@ def upload_core_to_github():
ssh_key = path('${core_plugin_ssh_key}')
if not is_windows():
# Prevent clone failing due to lacking access restrictions:
- run(['chmod', '600', ssh_key])
+ run(['chmod', '600', ssh_key], check=True)
with TemporaryDirectory() as tmp_dir:
cwd_before = getcwd()
chdir(tmp_dir)
@@ -118,7 +118,7 @@ def upload_core_to_github():
if not line.startswith('#') and line.rstrip()
}
for name in listdir(tmp_dir):
- if name not in extra_files:
+ if name not in extra_files and name != '.git':
if isdir(name):
rmtree(name)
else:
@@ -146,8 +146,11 @@ def upload_core_to_github():
def record_release_on_server():
import requests
- response = requests.post(SETTINGS['record_release_url'], {
+ url = SETTINGS['record_release_url']
+ if not url.startswith('https://'):
+ raise ValueError('record_release_url must use HTTPS')
+ response = requests.post(url, {
'secret': SETTINGS['server_api_secret'],
'version': SETTINGS['version']
- })
+ }, timeout=30)
response.raise_for_status()
\ No newline at end of file
diff --git a/src/build/settings/windows.json b/src/build/settings/windows.json
index 267f4713..bb66039d 100644
--- a/src/build/settings/windows.json
+++ b/src/build/settings/windows.json
@@ -4,5 +4,5 @@
"win32com.shell.shellcon", "win32gui", "winpty", "win32wnet"
],
"windows_sign_pass": "Tu4suttmdpn",
- "windows_sign_server": "http://sha256timestamp.ws.symantec.com/sha256/timestamp"
+ "windows_sign_server": "http://timestamp.digicert.com"
}
\ No newline at end of file
diff --git a/src/main/python/fman/__init__.py b/src/main/python/fman/__init__.py
index ab1f58d1..eefe7c12 100644
--- a/src/main/python/fman/__init__.py
+++ b/src/main/python/fman/__init__.py
@@ -41,6 +41,8 @@
DATA_DIRECTORY = expanduser('~/Library/Application Support/fman')
elif PLATFORM == 'Linux':
DATA_DIRECTORY = expanduser('~/.config/fman')
+else:
+ raise NotImplementedError('Unsupported platform: %s' % PLATFORM)
class ApplicationCommand:
def __init__(self, window):
diff --git a/src/main/python/fman/fs.py b/src/main/python/fman/fs.py
index 2cf8f00f..d020a0a7 100644
--- a/src/main/python/fman/fs.py
+++ b/src/main/python/fman/fs.py
@@ -146,7 +146,7 @@ def prepare_trash(self, path):
raise self._operation_not_implemented()
return [Task(
'Deleting ' + path.rsplit('/', 1)[-1],
- fn=self.delete, args=(path,), size=1
+ fn=self.move_to_trash, args=(path,), size=1
)]
def touch(self, path):
raise self._operation_not_implemented()
diff --git a/src/main/python/fman/impl/model/table.py b/src/main/python/fman/impl/model/table.py
index 33fe1c80..c1d17ff6 100644
--- a/src/main/python/fman/impl/model/table.py
+++ b/src/main/python/fman/impl/model/table.py
@@ -151,7 +151,7 @@ def insert(self, rows, first_rownum):
new_keys = {row.key: first_rownum + i for i, row in enumerate(rows)}
with self._lock:
# Perform this check here, once we have the lock:
- if first_rownum < 0 or first_rownum > len(self._rows) + 1:
+ if first_rownum < 0 or first_rownum > len(self._rows):
raise ValueError('Invalid first_rownum: %d' % first_rownum)
num_rows = len(rows)
for row in self._rows[first_rownum:]:
diff --git a/src/main/python/fman/impl/model/worker.py b/src/main/python/fman/impl/model/worker.py
index 51066233..df74de27 100644
--- a/src/main/python/fman/impl/model/worker.py
+++ b/src/main/python/fman/impl/model/worker.py
@@ -21,7 +21,7 @@ def submit(self, priority, fn, *args, **kwargs):
with self._shutdown_lock:
if self._shutdown:
return
- self._queue.put(WorkItem(priority, fn, *args, *kwargs))
+ self._queue.put(WorkItem(priority, fn, *args, **kwargs))
def shutdown(self):
with self._shutdown_lock:
self._shutdown = True
@@ -56,7 +56,7 @@ def __lt__(self, other):
return NotImplemented
def __eq__(self, other):
try:
- return self._fn, self._args, self._kwargs, self._priority == \
- other._fn, other._args, other._kwargs, other._priority
+ return (self._fn, self._args, self._kwargs, self._priority) == \
+ (other._fn, other._args, other._kwargs, other._priority)
except AttributeError:
return NotImplemented
\ No newline at end of file
diff --git a/src/main/python/fman/impl/plugins/command_registry.py b/src/main/python/fman/impl/plugins/command_registry.py
index e7204763..7bb1a0e6 100644
--- a/src/main/python/fman/impl/plugins/command_registry.py
+++ b/src/main/python/fman/impl/plugins/command_registry.py
@@ -153,9 +153,11 @@ def _set_context(self, pane, file_under_cursor=_DEFAULT):
if file_under_cursor is not self._DEFAULT:
cm = pane._override_file_under_cursor(file_under_cursor)
cm.__enter__()
- yield
- if file_under_cursor is not self._DEFAULT:
- cm.__exit__(None, None, None)
+ try:
+ yield
+ finally:
+ if file_under_cursor is not self._DEFAULT:
+ cm.__exit__(None, None, None)
def _get_default_aliases(cmd_class):
return re.sub(r'([a-z])([A-Z])', r'\1 \2', cmd_class.__name__)\
diff --git a/src/main/python/fman/impl/plugins/error.py b/src/main/python/fman/impl/plugins/error.py
index 8b19d965..c6797555 100644
--- a/src/main/python/fman/impl/plugins/error.py
+++ b/src/main/python/fman/impl/plugins/error.py
@@ -46,8 +46,8 @@ def handle_system_exit(self, code=0):
self._app.exit(code)
def on_main_window_shown(self, main_window):
self._main_window = main_window
- if self._pending_error_messages:
- self._main_window.show_alert(self._pending_error_messages[0])
+ for message in self._pending_error_messages:
+ self._main_window.show_alert(message)
def _get_plugin_traceback(self, exc):
if isinstance(exc, ThemeError):
return exc.description
diff --git a/src/main/python/fman/impl/session.py b/src/main/python/fman/impl/session.py
index 58278245..18144e70 100644
--- a/src/main/python/fman/impl/session.py
+++ b/src/main/python/fman/impl/session.py
@@ -68,13 +68,6 @@ def _show_startup_messages(self, main_window):
'Updated to v%s. ' \
'Changelog' % self._fman_version
main_window.show_status_message(status_message, timeout_secs=5)
- def _get_startup_message(self):
- previous_version = self._settings.get('fman_version', None)
- if not previous_version or previous_version == self._fman_version:
- return 'v%s ready.' % self._fman_version
- return 'Updated to v%s. ' \
- 'Changelog' \
- % self._fman_version
def _init_panes(self, panes, pane_infos, paths_on_cmdline):
with ThreadPoolExecutor(max_workers=len(panes)) as executor:
futures = [
diff --git a/src/main/python/fman/impl/util/path.py b/src/main/python/fman/impl/util/path.py
index b5ffff8a..7105975f 100644
--- a/src/main/python/fman/impl/util/path.py
+++ b/src/main/python/fman/impl/util/path.py
@@ -34,5 +34,8 @@ def normalize(path_):
if path_ == '.':
path_ = ''
# Resolve a/../b
- path_ = re.subn(r'(^|/)([^/]+)/\.\.(?:$|/)', r'\1', path_)[0]
+ while True:
+ path_, count = re.subn(r'(^|/)([^/]+)/\.\.(?:$|/)', r'\1', path_)
+ if not count:
+ break
return path_.rstrip('/')
\ No newline at end of file
diff --git a/src/main/python/fman/impl/util/qt/__init__.py b/src/main/python/fman/impl/util/qt/__init__.py
index 9d77ee96..8baddbad 100644
--- a/src/main/python/fman/impl/util/qt/__init__.py
+++ b/src/main/python/fman/impl/util/qt/__init__.py
@@ -16,8 +16,9 @@ def disable_window_animations_mac(window):
# penalties and leads to subtle changes in behaviour. We therefore wait for
# the Show event:
def eventFilter(target, event):
+ from ctypes import c_void_p
from objc import objc_object
- view = objc_object(c_void_p=int(target.winId()))
+ view = objc_object(c_void_p=c_void_p(int(target.winId())))
NSWindowAnimationBehaviorNone = 2
view.window().setAnimationBehavior_(NSWindowAnimationBehaviorNone)
FilterEventOnce(window, QEvent.Show, eventFilter)
diff --git a/src/main/python/fman/impl/widgets.py b/src/main/python/fman/impl/widgets.py
index c92c08fc..5a591d98 100644
--- a/src/main/python/fman/impl/widgets.py
+++ b/src/main/python/fman/impl/widgets.py
@@ -37,7 +37,7 @@ def exit(self, returnCode=0):
def set_style_sheet(self, stylesheet):
self.setStyleSheet(stylesheet)
def _on_state_changed(self, new_state):
- if new_state == Qt.ApplicationActive:
+ if new_state == Qt.ApplicationActive and self._main_window is not None:
for pane in self._main_window.get_panes():
pane.reload()
@@ -155,7 +155,7 @@ def get_sort_column(self):
return column, ascending
@run_in_main_thread
def get_column_widths(self):
- return [self._file_view.columnWidth(i) for i in (0, 1)]
+ return [self._file_view.columnWidth(i) for i in range(self._model.columnCount())]
@run_in_main_thread
def set_column_widths(self, column_widths):
num_columns = self._model.columnCount()
diff --git a/src/main/resources/base/Plugins/Core/core/commands/__init__.py b/src/main/resources/base/Plugins/Core/core/commands/__init__.py
index 319553d4..9d4c83b3 100644
--- a/src/main/resources/base/Plugins/Core/core/commands/__init__.py
+++ b/src/main/resources/base/Plugins/Core/core/commands/__init__.py
@@ -17,7 +17,7 @@
from io import UnsupportedOperation
from itertools import chain
from os import strerror
-from os.path import basename, pardir
+from os.path import pardir
from pathlib import PurePath
from PyQt5.QtCore import QUrl
from PyQt5.QtGui import QDesktopServices
@@ -1427,6 +1427,8 @@ def _get_matching_repos(self, query):
description=repo.description
)
def _install_plugin(self, name, zipball_contents):
+ if os.sep in name or '/' in name or '..' in name:
+ raise ValueError('Invalid plugin name: %s' % name)
os.makedirs(_THIRDPARTY_PLUGINS_DIR, exist_ok=True)
dest_dir = os.path.join(_THIRDPARTY_PLUGINS_DIR, name)
dest_dir_url = as_url(dest_dir)
@@ -1730,7 +1732,7 @@ def on_command(self, command_name, args):
except (KeyError, ValueError):
return None
if scheme == 'file://':
- new_scheme = _get_handler_for_archive(basename(path))
+ new_scheme = _get_handler_for_archive(basename(url))
if new_scheme:
try:
if is_dir(url):
diff --git a/src/main/resources/base/Plugins/Core/core/github.py b/src/main/resources/base/Plugins/Core/core/github.py
index d0c6b280..6db49e12 100644
--- a/src/main/resources/base/Plugins/Core/core/github.py
+++ b/src/main/resources/base/Plugins/Core/core/github.py
@@ -73,13 +73,14 @@ def _get_json(url):
def _get(url):
try:
- return urlopen(url).read()
+ with urlopen(url, timeout=30) as resp:
+ return resp.read()
except HTTPError:
raise
except URLError:
# Fallback: Some users get "SSL: CERTIFICATE_VERIFY_FAILED" for urlopen.
try:
- response = requests.get(url)
+ response = requests.get(url, timeout=30)
except RequestException as e:
raise URLError(e.__class__.__name__)
if response.status_code != 200:
diff --git a/src/main/resources/base/Plugins/Core/core/os_.py b/src/main/resources/base/Plugins/Core/core/os_.py
index 00205e99..6a1287f6 100644
--- a/src/main/resources/base/Plugins/Core/core/os_.py
+++ b/src/main/resources/base/Plugins/Core/core/os_.py
@@ -85,8 +85,11 @@ def _is_ubuntu():
except FileNotFoundError:
return False
+_ALLOWED_POPEN_KEYS = {'args', 'cwd', 'env', 'startupinfo'}
+
def _run_app_from_setting(app, curr_dir):
popen_kwargs = strformat_dict_values(app, {'curr_dir': curr_dir})
+ popen_kwargs = {k: v for k, v in popen_kwargs.items() if k in _ALLOWED_POPEN_KEYS}
Popen(**popen_kwargs)
def _is_gnome_based():
@@ -100,6 +103,7 @@ def _get_os_release_name():
if line.startswith('NAME='):
name = line[len('NAME='):]
return name.strip('"')
+ return ''
_FOCUS_PREVENTION_LEVEL = \
'/org/compiz/profiles/unity/plugins/core/focus-prevention-level'
\ No newline at end of file
diff --git a/src/main/resources/base/Plugins/Core/core/tests/fs/test_zip.py b/src/main/resources/base/Plugins/Core/core/tests/fs/test_zip.py
index 837f2bc2..a68a38d6 100644
--- a/src/main/resources/base/Plugins/Core/core/tests/fs/test_zip.py
+++ b/src/main/resources/base/Plugins/Core/core/tests/fs/test_zip.py
@@ -351,7 +351,7 @@ def _read_directory(self, dir_path):
child_contents = self._read_directory(child)
else:
child_contents = child.read_text()
- result[child.name] = child_contents
+ result[normalize('NFC', child.name)] = child_contents
return result
def _expect_zip_contents(self, contents, zip_file_path):
with TemporaryDirectory() as tmp_dir:
diff --git a/src/repo/fedora/fman.repo b/src/repo/fedora/fman.repo
index 06cbb5fc..1354f2b9 100644
--- a/src/repo/fedora/fman.repo
+++ b/src/repo/fedora/fman.repo
@@ -2,4 +2,5 @@
name=fman
baseurl=https://download.fman.io/rpm
enabled=1
-gpgcheck=0
\ No newline at end of file
+gpgcheck=1
+gpgkey=https://download.fman.io/rpm/public.gpg
\ No newline at end of file