Compare commits
	
		
			8 Commits
		
	
	
		
			b12395621d
			...
			723c5b6677
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 723c5b6677 | |||
| aaf8b12549 | |||
| 06e79d0679 | |||
| ff786e3ce6 | |||
| add9d858d8 | |||
| 731c507b95 | |||
| 62063a1448 | |||
| 1fb4e4efc5 | 
							
								
								
									
										2
									
								
								.gitattributes
									
									
									
									
										vendored
									
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										2
									
								
								.gitattributes
									
									
									
									
										vendored
									
									
								
							| @ -0,0 +1,2 @@ | ||||
| releases/tar/** filter=lfs diff=lfs merge=lfs -text | ||||
| releases/whl/** filter=lfs diff=lfs merge=lfs -text | ||||
							
								
								
									
										2
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										2
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							| @ -13,3 +13,5 @@ d2/book1/books | ||||
| .vscode/* | ||||
| !.vscode/launch.json | ||||
| python/build | ||||
| .*.kate-swp | ||||
| !releases/whl/*.whl | ||||
|  | ||||
							
								
								
									
										22
									
								
								Makefile
									
									
									
									
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										22
									
								
								Makefile
									
									
									
									
									
								
							| @ -1,10 +1,13 @@ | ||||
| .PHONY: python_clean_online_fxreader_vpn | ||||
| 
 | ||||
| host_deps: | ||||
| 	./m host_deps | ||||
| 	./m.py host_deps | ||||
| 
 | ||||
| python_lint: | ||||
| 	./m mypy -- -f vscode 2>&1 | less | ||||
| 	./m.py mypy -- -f vscode 2>&1 | less | ||||
| 
 | ||||
| python_tests: | ||||
| 	./m.py tests | ||||
| 
 | ||||
| #python_clean_online_fxreader_vpn:
 | ||||
| #	rm -fr \
 | ||||
| @ -48,6 +51,12 @@ python_put_dist: | ||||
| 	done | ||||
| 	ln -sf $(INSTALL_ROOT)/env3/bin/online-fxreader-pr34-commands $(INSTALL_ROOT)/commands | ||||
| 
 | ||||
| PYTHON_PROJECTS_NAMES ?= online.fxreader.pr34 | ||||
| python_whl: | ||||
| 	for f in $(PYTHON_PROJECTS_NAMES); do \
 | ||||
| 		./m.py deploy:wheel -o releases/whl -p $$f; \
 | ||||
| 	done | ||||
| 
 | ||||
| python_put: python_put_dist python_put_env | ||||
| 
 | ||||
| dotfiles_put: | ||||
| @ -77,3 +86,12 @@ dotfiles_fetch: | ||||
| 	commands install -f -p ~ -s ~/.config/katerc -t dotfiles | ||||
| 	commands install -f -p ~ -s ~/.config/Code\ -\ OSS/User/keybindings.json -t dotfiles | ||||
| 	commands install -f -p ~ -s ~/.config/Code\ -\ OSS/User/settings.json -t dotfiles | ||||
| 
 | ||||
| DOTFILES_VERSION ?= 0.1 | ||||
| 
 | ||||
| dotfiles_deploy: | ||||
| 	mkdir -p releases/tar | ||||
| 	tar -cvf - \
 | ||||
| 		dotfiles \
 | ||||
| 	| xz --compress -9 --stdout > \
 | ||||
| 	releases/tar/dotfiles-$(DOTFILES_VERSION).tar.xz | ||||
|  | ||||
							
								
								
									
										2
									
								
								deps/com.github.aiortc.aiortc
									
									
									
									
										vendored
									
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										2
									
								
								deps/com.github.aiortc.aiortc
									
									
									
									
										vendored
									
									
								
							| @ -1 +1 @@ | ||||
| Subproject commit 7552bcde773823c51c82daa5d9b23ea045df9ec2 | ||||
| Subproject commit 41fb87dc48ca2b0710e8489fc2de64f1fc82cf15 | ||||
| @ -19,7 +19,8 @@ set $term weston-terminal | ||||
| # on the original workspace that the command was run on. | ||||
| #for_window [app_id="^launcher$"] floating enable, sticky enable, resize set 30 ppt 60 ppt, border pixel 10 | ||||
| #set $menu exec $term --class=launcher -e /usr/bin/sway-launcher-desktop | ||||
| set $dmenu_path /usr/bin/bemenu-run | ||||
| #set $dmenu_path /usr/bin/bemenu-run | ||||
| set $dmenu_path rofi -modes run -show run | ||||
| set $menu $dmenu_path | xargs swaymsg exec -- | ||||
| 
 | ||||
| 
 | ||||
| @ -64,10 +65,12 @@ bindgesture swipe:4:right workspace prev | ||||
| 
 | ||||
| for_window [shell="xwayland"] title_format "[XWayland] %title" | ||||
| 
 | ||||
| #set $lock_cmd \ | ||||
| #    loginctl list-sessions | \ | ||||
| #    tail '-n' +2 | head -n -2 | awk '{print $1}' | \ | ||||
| #    xargs loginctl lock-session | ||||
| set $lock_cmd \ | ||||
|     loginctl list-sessions | \ | ||||
|     tail '-n' +2 | head -n -2 | awk '{print $1}' | \ | ||||
|     xargs loginctl lock-session | ||||
|     zsh -c "commands loginctl --action lock-session" | ||||
| 
 | ||||
| bindgesture swipe:4:up exec $lock_cmd | ||||
| 
 | ||||
| @ -76,14 +79,14 @@ bindgesture swipe:4:up exec $lock_cmd | ||||
| # | ||||
| # Basics: | ||||
| # | ||||
| bindsym $mod+Shift+l exec $lock_cmd | ||||
| bindsym Shift+$mod+l exec $lock_cmd | ||||
| 
 | ||||
| bindsym Shift+mod1+1 \ | ||||
| bindsym --locked Shift+mod1+1 \ | ||||
|     exec ~/.local/bin/commands \ | ||||
|         desktop-services \ | ||||
|         --cpufreq-action performance | ||||
| 
 | ||||
| bindsym Shift+mod1+2 \ | ||||
| bindsym --locked Shift+mod1+2 \ | ||||
|     exec ~/.local/bin/commands \ | ||||
|         desktop-services \ | ||||
|         --cpufreq-action powersave | ||||
| @ -140,7 +143,11 @@ floating_modifier $mod normal | ||||
| bindsym $mod+Shift+c reload | ||||
| 
 | ||||
| # Exit sway (logs you out of your Wayland session) | ||||
| bindsym $mod+Shift+e exec swaynag -t warning -m 'You pressed the exit shortcut. Do you really want to exit sway? This will end your Wayland session.' -b 'Yes, exit sway' 'swaymsg exit' | ||||
| bindsym $mod+Shift+e \ | ||||
| 	exec swaynag -t warning \ | ||||
| 	-m 'You pressed the exit shortcut. Do you really want to exit sway? This will end your Wayland session.' \ | ||||
| 	-b 'Yes, exit sway' \ | ||||
| 	'swaymsg exit' | ||||
| # | ||||
| # Moving around: | ||||
| # | ||||
| @ -224,7 +231,8 @@ bindsym $mod+p floating toggle | ||||
| ## Swap focus between the tiling area and the floating area | ||||
| #bindsym $mod+space focus mode_toggle | ||||
| 
 | ||||
| bindsym --release Print exec bash -c "commands wl-screenshot" | ||||
| bindsym --release Print exec zsh -c "commands wl-screenshot" | ||||
| bindsym --release $mod+s exec zsh -c "commands wl-screenshot" | ||||
| 
 | ||||
| # Move focus to the parent container | ||||
| #bindsym $mod+a focus parent | ||||
| @ -265,6 +273,40 @@ mode "resize" { | ||||
| } | ||||
| bindsym $mod+r mode "resize" | ||||
| 
 | ||||
| set $black	#000000 | ||||
| set $red		#ff0000 | ||||
| set $green	#00ff00 | ||||
| set $blue		#0000ff | ||||
| set $white	#ffffff | ||||
| set $grey		#757575 | ||||
| set $pale_green #9df882 | ||||
| set $pale_green2 #6baf54 | ||||
| set $dark_green #1a7000 | ||||
| set $pale_blue #7da9f9 | ||||
| set $dark_blue #005ba6 | ||||
| set $pale_greenblue #2da078 | ||||
| set $pale_greenblue2 #66c473 | ||||
| set $yellow #fffd0d | ||||
| set $dark_yellow #908f00 | ||||
| 
 | ||||
| set $color1 #18ff00 | ||||
| set $color2 #000000 | ||||
| set $color3 #ff00ff | ||||
| set $color4 #ff0000 | ||||
| set $color5 #00000000 | ||||
| set $color6 #00000000 | ||||
| set $color7 #00000000 | ||||
| 
 | ||||
| set $border_focused $pale_green | ||||
| set $border_unfocused $color2 | ||||
| set $background_focused $pale_greenblue2 | ||||
| set $background_unfocused $grey | ||||
| set $child_border_focused $white | ||||
| set $child_border_unfocused $color2 | ||||
| 
 | ||||
| set $bright_text $white | ||||
| set $dark_text $black | ||||
| 
 | ||||
| # | ||||
| # Status Bar: | ||||
| # | ||||
| @ -284,27 +326,34 @@ bar { | ||||
|     height 16 | ||||
| 
 | ||||
|     colors { | ||||
|         statusline #565656 | ||||
|         background #dfdfdf | ||||
|         inactive_workspace #dfdfdf #dfdfdf #000000 | ||||
|         active_workspace #dfdfdf #efefef #000000 | ||||
|         focused_workspace #dfdfdf #efefef #000000 | ||||
|         statusline $bright_text | ||||
|         background $pale_green2 | ||||
|         inactive_workspace $black $white $dark_text | ||||
|         active_workspace $black $white $bright_text | ||||
|         focused_workspace $dark_yellow $yellow $dark_text | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| client.focused #f3f3f3 #dfdfdf #565656 #f3f3f3 #f3f3f3 | ||||
| client.unfocused #f3f3f3 #dfdfdf #565656 #f3f3f3 #f3f3f3 | ||||
| 
 | ||||
| #client.focused #f3f3f3 #dfdfdfdd #565656 #f3f3f3 #f3f3f3 | ||||
| client.focused $border_focused $background_focused $white $white $child_border_focused | ||||
| client.unfocused $border_unfocused $background_unfocused $white $white $child_border_unfocused | ||||
| 
 | ||||
| for_window [all] border 1 | ||||
| 
 | ||||
| #font pango:Helvetica Neue 10 | ||||
| font pango:Terminus 10 | ||||
| font pango:Terminus 12 | ||||
| 
 | ||||
| titlebar_padding 1 4 | ||||
| titlebar_padding 32 1 | ||||
| titlebar_border_thickness 1 | ||||
| title_align center | ||||
| 
 | ||||
| #for_window [class=".*"] title_format "<b>%title</b>" | ||||
| 
 | ||||
| for_window [class="^firefox$"] floating enable | ||||
| 
 | ||||
| for_window [all] opacity set 0.95 | ||||
| 
 | ||||
| input * { | ||||
|     xkb_layout "us,ru" | ||||
|     xkb_options "grp:win_space_toggle" | ||||
| @ -313,4 +362,3 @@ input type:keyboard xkb_model "pc101" | ||||
| 
 | ||||
| include /etc/sway/config.d/* | ||||
| include ~/.sway/config.d/* | ||||
| 
 | ||||
|  | ||||
							
								
								
									
										77
									
								
								m.py
									
									
									
									
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										77
									
								
								m.py
									
									
									
									
									
								
							| @ -17,7 +17,10 @@ logger = logging.getLogger(__name__) | ||||
| class PyProject: | ||||
|     dependencies: dict[str, list[str]] | ||||
|     early_features: Optional[list[str]] = None | ||||
|      | ||||
|     pip_find_links: Optional[list[pathlib.Path]] = None | ||||
|     runtime_libdirs: Optional[list[pathlib.Path]] = None | ||||
|     runtime_preload: Optional[list[pathlib.Path]] = None | ||||
| 
 | ||||
| def pyproject_load( | ||||
|     d: pathlib.Path, | ||||
| ) -> PyProject: | ||||
| @ -42,7 +45,7 @@ def pyproject_load( | ||||
|             assert isinstance(v, list) | ||||
|             assert isinstance(k, str) | ||||
| 
 | ||||
|         dependencies[k] = v | ||||
|             dependencies[k] = v | ||||
| 
 | ||||
| 
 | ||||
|     res = PyProject( | ||||
| @ -65,6 +68,26 @@ def pyproject_load( | ||||
|         if 'early_features' in content['tool'][tool_name]: | ||||
|             res.early_features = content['tool'][tool_name]['early_features'] | ||||
| 
 | ||||
|         if 'pip_find_links' in content['tool'][tool_name]: | ||||
|             res.pip_find_links = [ | ||||
|                 d.parent / pathlib.Path(o) | ||||
|                 for o in content['tool'][tool_name]['pip_find_links'] | ||||
|             ] | ||||
| 
 | ||||
|         if 'runtime_libdirs' in content['tool'][tool_name]: | ||||
|             res.runtime_libdirs = [ | ||||
|                 d.parent / pathlib.Path(o) | ||||
|                 # pathlib.Path(o) | ||||
|                 for o in content['tool'][tool_name]['runtime_libdirs'] | ||||
|             ] | ||||
| 
 | ||||
|         if 'runtime_preload' in content['tool'][tool_name]: | ||||
|             res.runtime_preload = [ | ||||
|                 d.parent / pathlib.Path(o) | ||||
|                 # pathlib.Path(o) | ||||
|                 for o in content['tool'][tool_name]['runtime_preload'] | ||||
|             ] | ||||
| 
 | ||||
|     return res | ||||
| 
 | ||||
| @dataclasses.dataclass | ||||
| @ -92,8 +115,21 @@ def env_bootstrap( | ||||
|     bootstrap_settings: BootstrapSettings, | ||||
|     pyproject: PyProject, | ||||
| ) -> None: | ||||
|     pip_find_links : list[pathlib.Path] = [] | ||||
| 
 | ||||
|     if not pyproject.pip_find_links is None: | ||||
|         pip_find_links.extend(pyproject.pip_find_links) | ||||
| 
 | ||||
|     pip_find_links_args = sum([ | ||||
|         ['-f', str(o),] | ||||
|         for o in pip_find_links | ||||
|     ], []) | ||||
| 
 | ||||
|     subprocess.check_call([ | ||||
|         'uv', 'venv', '--seed', | ||||
|         'uv', 'venv', | ||||
|         *pip_find_links_args, | ||||
|         # '--seed', | ||||
|         '--offline', | ||||
|         str(bootstrap_settings.env_path) | ||||
|     ]) | ||||
| 
 | ||||
| @ -101,31 +137,36 @@ def env_bootstrap( | ||||
|         'uv', | ||||
|         'pip', | ||||
|         'install', | ||||
|         *pip_find_links_args, | ||||
|         '-p', | ||||
|         bootstrap_settings.python_path, | ||||
|         'uv', | ||||
|         '--offline', | ||||
|         'uv', 'pip', | ||||
|     ]) | ||||
| 
 | ||||
|     subprocess.check_call([ | ||||
|         bootstrap_settings.python_path, | ||||
|         '-m', | ||||
|         'uv', 'pip', 'install', | ||||
|         *pip_find_links_args, | ||||
|         '--offline', | ||||
|         'build', 'setuptools', 'meson-python', 'pybind11', | ||||
|     ]) | ||||
| 
 | ||||
|     early_wheels = glob.glob( | ||||
|         str( | ||||
|             pathlib.Path(__file__).parent / 'deps' / 'dist' / 'early' / '*.whl' | ||||
|         ) | ||||
|     ) | ||||
|     # early_wheels = glob.glob( | ||||
|     #     str( | ||||
|     #         pathlib.Path(__file__).parent / 'deps' / 'dist' / 'early' / '*.whl' | ||||
|     #     ) | ||||
|     # ) | ||||
| 
 | ||||
|     if len(early_wheels) > 0: | ||||
|         subprocess.check_call([ | ||||
|             bootstrap_settings.python_path, | ||||
|             '-m', | ||||
|             'uv', 'pip', 'install', | ||||
|             *early_wheels, | ||||
|         ]) | ||||
|     # if len(early_wheels) > 0: | ||||
|     #     subprocess.check_call([ | ||||
|     #         bootstrap_settings.python_path, | ||||
|     #         '-m', | ||||
|     #         'uv', 'pip', 'install', | ||||
|     #         '--offline', | ||||
|     #         *early_wheels, | ||||
|     #     ]) | ||||
| 
 | ||||
|     if pyproject.early_features: | ||||
|         early_dependencies = sum([ | ||||
| @ -136,11 +177,15 @@ def env_bootstrap( | ||||
|         logger.info(dict( | ||||
|             early_dependencies=early_dependencies, | ||||
|         )) | ||||
| 
 | ||||
|         if len(early_dependencies) > 0: | ||||
|             subprocess.check_call([ | ||||
|                 bootstrap_settings.python_path, | ||||
|                 '-m', | ||||
|                 'uv', 'pip', 'install', | ||||
|                 *pip_find_links_args, | ||||
|                 # '-f', str(pathlib.Path(__file__).parent / 'deps' / 'dist'), | ||||
|                 '--offline', | ||||
|                 *early_dependencies, | ||||
|             ]) | ||||
| 
 | ||||
|  | ||||
| @ -26,6 +26,7 @@ logger = logging.getLogger(__name__) | ||||
| class Command(enum.StrEnum): | ||||
|     mypy = 'mypy' | ||||
|     deploy_wheel = 'deploy:wheel' | ||||
|     tests = 'tests' | ||||
| 
 | ||||
| @dataclasses.dataclass | ||||
| class Settings( | ||||
| @ -145,8 +146,17 @@ class CLI(_cli.CLI): | ||||
|             self.mypy( | ||||
|                 argv=args, | ||||
|             ) | ||||
|         elif options.command is Command.tests: | ||||
|             for k, v in self.projects.items(): | ||||
|                 subprocess.check_call([ | ||||
|                     sys.executable, | ||||
|                     '-m', | ||||
|                     'unittest', | ||||
|                     'online.fxreader.pr34.tests.test_crypto', | ||||
|                     *args, | ||||
|                 ], cwd=str(v.source_dir)) | ||||
|         else: | ||||
|             raise NotImplementedError | ||||
| 
 | ||||
| if __name__ == '__main__': | ||||
|     CLI().run() | ||||
|     CLI().run() | ||||
|  | ||||
| @ -971,23 +971,34 @@ def resilient_vlc(stream=None): | ||||
|                             pass | ||||
|         time.sleep(1.0) | ||||
| 
 | ||||
| def sway_sock(): | ||||
|     import glob | ||||
|     uid = os.stat(os.environ['HOME']).st_uid | ||||
|     t1 = glob.glob( | ||||
|         os.path.join( | ||||
|             '/run', | ||||
|             'user', | ||||
|             '%d' % uid, | ||||
|             'sway-ipc.%d*.sock' % uid, | ||||
| def sway_sock( | ||||
|     wait: bool = False, | ||||
| ) -> Optional[str]: | ||||
|     while True: | ||||
|         import glob | ||||
|         uid = os.stat(os.environ['HOME']).st_uid | ||||
|         t1 = glob.glob( | ||||
|             os.path.join( | ||||
|                 '/run', | ||||
|                 'user', | ||||
|                 '%d' % uid, | ||||
|                 'sway-ipc.%d*.sock' % uid, | ||||
|             ) | ||||
|         ) | ||||
|     ) | ||||
|     t2 = [ | ||||
|         os.stat(o).st_mtime | ||||
|         for o in t1 | ||||
|     ] | ||||
|     t3 = sorted(enumerate(t1), key=lambda x: t2[x[0]])[-1][0] | ||||
|     return t1[t3] | ||||
|         t2 = [ | ||||
|             os.stat(o).st_mtime | ||||
|             for o in t1 | ||||
|         ] | ||||
|         sorted_entries = sorted(enumerate(t1), key=lambda x: t2[x[0]]) | ||||
|         if len(sorted_entries) > 0: | ||||
|             t3 = sorted_entries[-1][0] | ||||
|             return t1[t3] | ||||
|         else: | ||||
|             if wait: | ||||
|                 time.sleep(0.1) | ||||
|                 continue | ||||
|             else: | ||||
|                 return None | ||||
| 
 | ||||
| def eternal_firefox( | ||||
|     tabs=None, | ||||
| @ -2084,6 +2095,25 @@ def scrap_yt_music(argv: list[str]) -> None: | ||||
|     for o in context['workers']: | ||||
|         o.join() | ||||
| 
 | ||||
| def loginctl(argv: list[str]) -> None: | ||||
|     parser = argparse.ArgumentParser() | ||||
|     parser.add_argument( | ||||
|         '--action', | ||||
|         choices=[ | ||||
|             'lock-session', | ||||
|         ], | ||||
|     ) | ||||
| 
 | ||||
|     options = parser.parse_args(argv) | ||||
| 
 | ||||
|     if options.action == 'lock-session': | ||||
|         subprocess.check_call(r''' | ||||
|             loginctl list-sessions -j | jq -r ".[] | select(.uid==$UID) | \ | ||||
|             .session" | loginctl lock-session | ||||
|         ''', shell=True, timeout=1) | ||||
|     else: | ||||
|         raise NotImplementedError | ||||
| 
 | ||||
| def desktop_services(argv): | ||||
|     parser = optparse.OptionParser() | ||||
|     parser.add_option( | ||||
| @ -2606,7 +2636,15 @@ echo 6500 > /sys/bus/platform/devices/applesmc.768/fan1_output; | ||||
|     else: | ||||
|         pass | ||||
| 
 | ||||
|     os.environ['SWAYSOCK'] = sway_sock() | ||||
|     #logger.info(dict( | ||||
|     #    environ=os.environ, | ||||
|     #    #session=subprocess.check_output(['loginctl', 'show-session'], timeout=1,), | ||||
|     #)) | ||||
| 
 | ||||
|     sway_sock_res = sway_sock(True) | ||||
| 
 | ||||
|     if sway_sock_res: | ||||
|         os.environ['SWAYSOCK'] = sway_sock_res | ||||
| 
 | ||||
|     assert all([ | ||||
|         env_name in os.environ | ||||
| @ -2614,7 +2652,8 @@ echo 6500 > /sys/bus/platform/devices/applesmc.768/fan1_output; | ||||
|             'GTK_IM_MODULE', | ||||
|             'XMODIFIERS', | ||||
|             'QT_IM_MODULE', | ||||
|             'I3SOCK', | ||||
|             #'I3SOCK', | ||||
|             #'XDG_SEAT', | ||||
|             'SWAYSOCK', | ||||
|             'WAYLAND_DISPLAY', | ||||
|         ] | ||||
| @ -2684,7 +2723,8 @@ echo 6500 > /sys/bus/platform/devices/applesmc.768/fan1_output; | ||||
|                     unlock='echo unlock; pkill --signal SIGINT swaylock; swaymsg "output * dpms on";', | ||||
|                     unlock2='pkill --signal SIGINT swaylock;', | ||||
|                     resume='echo resume; swaymsg "output * dpms on";', | ||||
|                     before_sleep='echo before_sleep; loginctl lock-session;', | ||||
|                     before_sleep='echo before_sleep; commands loginctl lock-session;', | ||||
|                     #before_sleep='echo blah;', | ||||
|                     after_resume='echo after_resume; pkill --signal SIGUSR1 swayidle;', | ||||
|                 ) | ||||
|                 self.last_force_idle = None | ||||
| @ -3886,6 +3926,7 @@ class Command(enum.StrEnum): | ||||
|     socat_ssh = 'socat-ssh' | ||||
|     gnome_shortcuts = 'gnome-shortcuts' | ||||
|     sway_sock = 'sway_sock' | ||||
|     loginctl = 'loginctl' | ||||
|     suspend_timer = 'suspend-timer' | ||||
|     desktop_services = 'desktop-services' | ||||
|     pm_service = 'pm-service' | ||||
| @ -4027,6 +4068,8 @@ def commands_cli( | ||||
|                 gnome_shortcuts(args) | ||||
|             elif options.command is Command.sway_sock: | ||||
|                 print(sway_sock()) | ||||
|             elif options.command is Command.loginctl: | ||||
|                 loginctl(args) | ||||
|             elif options.command is Command.suspend_timer: | ||||
|                 suspend_timer(args) | ||||
|             elif options.command is Command.desktop_services: | ||||
|  | ||||
| @ -20,7 +20,7 @@ class PyProject: | ||||
|     pip_find_links: Optional[list[pathlib.Path]] = None | ||||
|     runtime_libdirs: Optional[list[pathlib.Path]] = None | ||||
|     runtime_preload: Optional[list[pathlib.Path]] = None | ||||
|      | ||||
| 
 | ||||
| def pyproject_load( | ||||
|     d: pathlib.Path, | ||||
| ) -> PyProject: | ||||
|  | ||||
							
								
								
									
										90
									
								
								python/online/fxreader/pr34/commands_typed/crypto.py
									
									
									
									
									
										Normal file
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										90
									
								
								python/online/fxreader/pr34/commands_typed/crypto.py
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,90 @@ | ||||
| import base64 | ||||
| import os | ||||
| 
 | ||||
| import cryptography.hazmat.primitives.kdf.scrypt | ||||
| 
 | ||||
| from typing import (Literal, overload, Optional,) | ||||
| 
 | ||||
| class PasswordUtils: | ||||
|   @overload | ||||
|   @classmethod | ||||
|   def secret_hash( | ||||
|     cls, | ||||
|     secret: str | bytes, | ||||
|     mode: Literal['base64'], | ||||
|     salt: Optional[bytes] = None, | ||||
|   ) -> tuple[str, str]: ... | ||||
| 
 | ||||
|   @overload | ||||
|   @classmethod | ||||
|   def secret_hash( | ||||
|     cls, | ||||
|     secret: str | bytes, | ||||
|     mode: Literal['bytes'], | ||||
|     salt: Optional[bytes] = None, | ||||
|   ) -> tuple[bytes, bytes]: ... | ||||
| 
 | ||||
|   @classmethod | ||||
|   def secret_hash( | ||||
|     cls, | ||||
|     secret: str | bytes, | ||||
|     mode: Literal['bytes', 'base64'], | ||||
|     salt: Optional[bytes] = None, | ||||
|   ) -> tuple[str, str] | tuple[bytes, bytes]: | ||||
|     if salt is None: | ||||
|       salt = os.urandom(16) | ||||
| 
 | ||||
|     if isinstance(secret, str): | ||||
|       secret = secret.encode('utf-8') | ||||
|     # derive | ||||
|     kdf = cls._scrypt_init(salt=salt) | ||||
| 
 | ||||
|     hashed_secret = kdf.derive(secret) | ||||
| 
 | ||||
|     if mode == 'bytes': | ||||
|       return (salt, hashed_secret) | ||||
|     elif mode == 'base64': | ||||
|       res_tuple = tuple(( | ||||
|         base64.b64encode(o).decode('utf-8') | ||||
|         for o in (salt, hashed_secret,) | ||||
|       )) | ||||
|       return (res_tuple[0], res_tuple[1]) | ||||
|     else: | ||||
|       raise NotImplementedError | ||||
| 
 | ||||
|   @classmethod | ||||
|   def _scrypt_init( | ||||
|     cls, | ||||
|     salt: bytes | ||||
|   ) -> cryptography.hazmat.primitives.kdf.scrypt.Scrypt: | ||||
|     return cryptography.hazmat.primitives.kdf.scrypt.Scrypt( | ||||
|       salt=salt, | ||||
|       length=32, | ||||
|       n=2**14, | ||||
|       r=8, | ||||
|       p=1, | ||||
|     ) | ||||
| 
 | ||||
|   @classmethod | ||||
|   def secret_check( | ||||
|     cls, | ||||
|     secret: str | bytes, | ||||
|     salt: str | bytes, | ||||
|     hashed_secret: str | bytes, | ||||
|   ) -> bool: | ||||
|     if isinstance(salt, str): | ||||
|       salt = base64.b64decode(salt) | ||||
| 
 | ||||
|     if isinstance(secret, str): | ||||
|       secret = secret.encode('utf-8') | ||||
| 
 | ||||
|     if isinstance(hashed_secret, str): | ||||
|       hashed_secret = base64.b64decode(hashed_secret) | ||||
| 
 | ||||
|     kdf = cls._scrypt_init(salt=salt) | ||||
| 
 | ||||
|     try: | ||||
|       kdf.verify(secret, hashed_secret) | ||||
|       return True | ||||
|     except cryptography.exceptions.InvalidKey: | ||||
|       return False | ||||
							
								
								
									
										0
									
								
								python/online/fxreader/pr34/tests/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										0
									
								
								python/online/fxreader/pr34/tests/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
								
								
									
										36
									
								
								python/online/fxreader/pr34/tests/test_crypto.py
									
									
									
									
									
										Normal file
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										36
									
								
								python/online/fxreader/pr34/tests/test_crypto.py
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,36 @@ | ||||
| from online.fxreader.pr34.commands_typed import crypto | ||||
| import unittest | ||||
| 
 | ||||
| 
 | ||||
| class TestCrypto(unittest.TestCase): | ||||
|     def test_password_utils(self) -> None: | ||||
|         salt = b'asdfasdfasdf' | ||||
| 
 | ||||
|         secret = 'blah' | ||||
| 
 | ||||
|         hash_res = crypto.PasswordUtils.secret_hash( | ||||
|             secret, | ||||
|             mode='bytes', | ||||
|             salt=salt, | ||||
|         ) | ||||
|         self.assertEqual( | ||||
|             hash_res, | ||||
|             ( | ||||
|                 salt, | ||||
|                 b'\xdak\xd15\xfa\x8e\xc8\r\xc3\xd2c\xf1m\xb0\xbf\xe6\x98\x01$!j\xc8\xc0Hh\x84\xea,\x91\x8b\x08\xce', | ||||
|             ), | ||||
|         ) | ||||
| 
 | ||||
|         check_res = crypto.PasswordUtils.secret_check( | ||||
|             secret, | ||||
|             *hash_res, | ||||
|         ) | ||||
| 
 | ||||
|         self.assertTrue(check_res) | ||||
| 
 | ||||
|         self.assertFalse( | ||||
|             crypto.PasswordUtils.secret_check( | ||||
|                 secret + 'asdfasdfsdf', | ||||
|                 *hash_res, | ||||
|             ) | ||||
|         ) | ||||
| @ -11,8 +11,13 @@ dependencies = [ | ||||
| ] | ||||
| 
 | ||||
| [project.optional-dependencies] | ||||
| crypto = [ | ||||
|     'cryptography', | ||||
| ] | ||||
| 
 | ||||
| early = [ | ||||
|     'numpy' | ||||
|     'numpy', | ||||
|     'cryptography', | ||||
| ] | ||||
| 
 | ||||
| [tool.online-fxreader-pr34] | ||||
|  | ||||
							
								
								
									
										
											BIN
										
									
								
								releases/tar/dotfiles-0.1.tar.xz
									 (Stored with Git LFS)
									
									
									
									
										Normal file
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										
											BIN
										
									
								
								releases/tar/dotfiles-0.1.tar.xz
									 (Stored with Git LFS)
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										
											BIN
										
									
								
								releases/whl/online_fxreader_pr34-0.1.4.13-py3-none-any.whl
									 (Stored with Git LFS)
									
									
									
									
										Normal file
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										
											BIN
										
									
								
								releases/whl/online_fxreader_pr34-0.1.4.13-py3-none-any.whl
									 (Stored with Git LFS)
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							
		Loading…
	
		Reference in New Issue
	
	Block a user