使用 Cython 加密 Python 项目

最近公司需要将 python 代码部署到端上查了各种加密方法说到底 python 其实是不建议加密部署的,像什么生成.pyc其实都是很容易反编译直接运行的,因为它是解释型语言。不像 C 或者 java 可以编译后生成机器码直接部署。还有看到把项目打包成.exe文件,在 windows 上运行,由于我们使用 Linux 平台没有尝试,最后选择了使用Cython这个库来加密(编译成二进制)。 Cython其实就是把py 代码编译成 C或者 C++代码来执行,在Linux 上会生成.so二进制文件,Windows下为.pyd,所以还有一个作用是加速代码的执行效率。但还有一些限制如项目中不能删除__init__.py否者包导入会失败。详细可参考官方文档,Cython 还在持续开发中支持 Python3,下面也用Python3演示。 先来做一些准备工作定义编译后的文件夹build和一些部署不需要的文件和文件夹,将待编译的.py文件加入ext_modules列表 cur_dir = os.path.abspath(os.path.dirname(__file__)) setup_file = os.path.split(__file__)[1] build_dir = os.path.join(cur_dir, 'build') build_tmp_dir = os.path.join(build_dir, "temp") # define exclude dirs, these dirs will be deleted exclude_dirs = ['.git', '__pycache__', 'test', 'logs', 'venv', 'tests'] # defile exclude files, these files will be deleted exclude_files = ['*.md', '.gitignore', '.python-version', 'requirements.txt', '*.pyc', '*.c'] # these `.py` files will be retained and don't compile to `.so` ignore_py_files = ['config.py'] ext_modules = [] # get all build files for path, dirs, files in os.walk(cur_dir, topdown=True): dirs[:] = [d for d in dirs if d not in exclude_dirs] # touch a new file when __init__.py not exists for _dir in dirs: init_file = os.path.join(path, _dir, '__init__.py') if not os.path.isfile(init_file): print('WARNING: create new empty [{}] file.'.format(init_file)) with open(init_file, 'a') as f: pass # create target folder if not os.path.isdir(build_dir): os.mkdir(build_dir) # make empty dirs for dir_name in dirs: dir = os.path.join(path, dir_name) target_dir = dir.replace(cur_dir, build_dir) os.mkdir(target_dir) for file_name in files: file = os.path.join(path, file_name) if os.path.splitext(file)[1] == '.py': if file_name in ignore_py_files: # don't compile to .so if file_name not in exclude_files: shutil.copy(file, path.replace(cur_dir, build_dir)) elif file_name in exclude_files: # remove it pass else: # add to compile if file_name == '__init__.py': # copy __init__.py resolve package cannot be imported shutil.copy(file, path.replace(cur_dir, build_dir)) if file_name != setup_file: ext_modules.append(file) else: _exclude = False for pattern in exclude_files: if fnmatch.fnmatch(file_name, pattern): _exclude = True if not _exclude: shutil.copy(file, path.replace(cur_dir, build_dir)) 我们需要把原来的每个文件夹下__init__.py拷贝一份,不然项目中相对导入这些会失效。然后把ext_modules列表传给cythonize生成distutils Extension objects再传给setup函数。 ...

November 3, 2018 · 2 min · 307 words · Fython

读《亲爱的安德烈》

今年的中秋和国庆只隔了一周的工作日,故中秋没回老家和两朋友去了东极岛看看海和吃了点海鲜惶惶三日,途中大巴车上用 kobo(类似 kindle)看了一半,国庆长假回乡见父母同学抽空书架上取出又看了一半。我可能守旧,能用实体书看的时候还是喜欢实体书的质感,捧着本书比 kobo 感觉更真实,但 kobo 能装下我书架上的所有书也方便易带和搜索,或许多年后实体书也会成为奢侈品吧。 这是本两代人中间差了 30 年的一共 36 封家书,但读来会惊讶母亲和儿子竟可以如此像朋友般对话沟通,涵盖了政治、艺术、人生、生活等等。于儿子更能明白为人父母的殷切期望不是能成才取得多大多大的成就而是只要你过得开心。当安德烈说我这辈子可能达不到父母的成就,可能只是一个平庸人时。龙妈妈这样回答 对我最重要的,安德烈,不是你有否成就,而是你是否快乐。而在现代的生活架构里,什么样的工作比较可能给你快乐?第一,它给你意义;第二,它给你时间。你的工作是你觉得有意义的,你的工作不绑架你使你成为工作的俘虏,容许你去充分体验生活,你就比较可能是快乐的。至于金钱和名声,哪里是快乐的核心元素呢?……我也要求你读书用功,不是因为我要你跟别人比成就,而是因为,我希望你将来有选择的权利,选择有意义、有时间的工作,而不是被迫谋生。……『平庸』是跟别人比,心灵的安适是跟自己比。我们最终极的负责对象,安德烈,千山万水走到最后,还是『自己』二字。 而在儿子为情所困时,妈妈等了好久既激动又兴奋 我愿意和你分享的是我自己的『心得报告』,那就是,人生就像条大河,可能风景清丽,更可能惊涛骇浪。你需要的伴侣,最好是那能够和你并肩而立在船头,浅吟低唱两岸风光,同时更能在惊涛骇浪中紧紧握住你的手不放的人。换句话说,最好她本身不是你必须应付的惊涛骇浪。 于父母时要明白当孩子已经 18 岁成人时他已经是一个独立的个体,他要为自己做的事情付全部的责任。如安德烈常抽烟,而且在母亲面前抽。每次见到妈妈恨不得跑过去抽两个耳光但你不能马上上去制止,因为他已成人已是一个独立的个体。 父母也会认识到孩子慢慢的长大,像小鸟一样终会飞走。当父母五六十岁孩子就会意识到回国头来慢慢看看,我还有父母这个窝。

October 7, 2018 · 1 min · 19 words · Fython

Systemd 中的timer单元

Systemd 中的 timer 单元 上一篇讲了 systemd 中的 service 单元,这次记录一下 timer 单元。timer 必须依赖 service 单元来配置,可以用来做替代 crontab 的选择。 timer 单元以.timer结尾,中间包含[Timer]块如下面所示是 Ubuntu 下的apt-daily.timer,该目录下也存在一个apt-daily.service服务文件配合一起使用。 [Unit] Description=Daily apt activities [Timer] OnCalendar=*-*-* 6,18:00 RandomizedDelaySec=12h AccuracySec=1h Persistent=true [Install] WantedBy=timers.target 上面的[Timer]块代表每天上午 6 点和下午 6 点都运行 apt 脚本,具体[Timer]块可配置以下参数 单调定时器(Monotonic timer) Option Description OnActiveSec= 相对计时器开始后多少时间执行,格式如 2h、2s、2w、2d OnBootSec= 相对系统启动后多少时间执行 OnStartupSec= 相对 systemd 启动多少时间后执行 OnUnitActiveSec= 每隔多少时间再次运行一次 OnUnitInactiveSec= 服务在最后一次停止后,隔多久再执行一次 可以两个参数一起使用,如下每周开机 15 分钟后执行 foo [Unit] Description=Run foo weekly and on boot [Timer] OnBootSec=15min OnUnitActiveSec=1w [Install] WantedBy=timers.target 实时定时器(Realtime timer) Option Description OnCalendar= 相对系统时间指定特定时刻运行,它接受如 2h、2s 的格式也可以是 星期 年-月-日 时:分:秒的格式,..指定区间,*代表所有的。可参考 systemd.time(7) Persistent= 是一个布尔值,默认为 no,当使用 OnCalendar 的设置时,指定该功能要不要持续进行。如断电恢复后是不是要执行上次没执行的 AccuracySec= 设置定时器的触发精度。默认值是一分钟。定时器并不必然在所设置的精准时间点上启动匹配单元, 而是在所设置的精准时间点为起点的一小段时间窗口范围内的某个时间点上启动匹配单元, 这个时间窗口的起点由 OnCalendar=, OnActiveSec=, OnBootSec=, OnStartupSec=, OnUnitActiveSec= or OnUnitInactiveSec= 决定, 而这个时间窗口的长度则由该指令决定。 RandomizedDelaySec= 将此单元的定时器随机延迟一小段时间, 这一小段时间的长度介于零到该指令设置的时间长度之间, 以均匀概率分布。 如下是每月的 1 到 4 号 12 点周一和周二运行 foo,格式如OnCalendar=*-*-* 4:00:00代表每天 4 点 ...

August 16, 2018 · 1 min · 210 words · Fython

Mac终端(Terminal)配置

Mac 终端(Terminal)配置 平时工作中命令行用的比图形界面多,所以有必要配置一个赏心悦目的终端界面来提高工作效率(^_^)。 iTerm 第一步就是替换原来的自带终端(Terminal),换成iTerm。iTerm 是一个深受广大开发者欢迎的终端 App,代码托管在Github,可以直接在官网下载安装。最新版为 Build 3.4.23 打开iTerm2 > Preferences > General,在Selection下勾上Applications in terminal may access clipboard使在iTerm中鼠标选中就能复制到系统剪切板使用command+v粘贴 打开iTerm2 > Preferences > Profiles,右边点Keys把左右 option 键设为Esc+,取消勾选Apps can change this来启用 Unix 的Alt + B和Alt + F前进和后退一个单词。 打开iTerm2 > Preferences > Terminal,底部 Shell Integration 取消勾选 Show mark indicators 不然每次执行命令会出现一个小箭头影响美观 Zsh & Oh My Zsh 打开 iTerm 安装Homebrew /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)" 使用 Homebrew 安装 zsh,设为默认的终端。从 Big Sur 已经设置 zsh 为默认的终端了,可以跳过此步骤,可以使用echo $SHELL检查 ...

July 23, 2018 · 1 min · 210 words · Fython

Systemd中Service单元介绍

Systemd中Service单元介绍 Systemd是一个系统管理守护进程、工具和库的集合,用于取代System V初始进程,集中管理和配置类UNIX系统,可见它非常的强大。 Systemd分为多个单元(unit)如服务(.service),挂载点(.mount),套接口(.socket)和设备(.device)等,这里记录使用最多的服务(service)文件的编写。用户自定义的一般存放在/etc/systemd/sytem/文件夹下,还有另外的文件夹类debian系列的如下。 Directory Description /lib/systemd/system/ 系统自带的或者程序自带安装的单元存放在此 /etc/systemd/system/ 用户自定义的,此文件夹优先级最高,可以覆盖上面文件夹的内容 下面是系统安装openssh-server后,在/lib/systemd/system/ssh.service下的服务。 [Unit] Description=OpenBSD Secure Shell server After=network.target auditd.service ConditionPathExists=!/etc/ssh/sshd_not_to_be_run [Service] EnvironmentFile=-/etc/default/ssh ExecStart=/usr/sbin/sshd -D $SSHD_OPTS ExecReload=/bin/kill -HUP $MAINPID KillMode=process Restart=on-failure RestartPreventExitStatus=255 Type=notify [Install] WantedBy=multi-user.target Alias=sshd.service 如上所示一般每个Unit都有各个块(section)组成,由[]包裹就是块名。下面的就是配置,直到另一个块开始为止。 [Unit] section [Unit]一般是第一个块文件配置,配置各种元数据(metadata)和其他单元的关系 Option Description Description= 这个单元的描述字符串 Documentation= 文档链接 Requires= 运行这个单元所需要的依赖单元,否则启动失败 Wants= 和上面Requires相似,但是非强限制。如果列出在此的单元没有启动,本单元也还是能启动持续运行 BindsTo= 和上面Requires相似,区别是列出在此的单元终止了,本单元也会停止 Before= 在此列出的单元,只有在本单元启动后才会启动。但不是依赖关系,如需依赖配置上述Requires命令 After= 在启动本单元之前,先要启动在此列出的单元。但不是依赖关系,如需依赖配置上述Requires命令 Conflicts= 在此列出的单元,不能和本单元同时运行,和Requires相反 OnFailure= 在此列出的单元将会在本单元失败后激活 还有很多的如Condition...和Assert...配置详情可以查看手册man 5 systemd.unit [Install] section [Install]一般是最后一个块文件配置,这个是可选项,也就是说可以不配置。只有在开机启动激活(enable)时触发。 Option Description WantedBy= 指定该单元如何开机启动(enable),依赖在此列出的单元,有点类似[Unit]块中的Wants,不同的是它会创建软链接到.wants文件夹,如上sshd如果被enable,该单元会创建一个软链接到/etc/systemd/system/multi-user.target.wants文件夹下,如果文件夹不存在则创建文件夹再软链接。 RequiredBy= 和上面WantedBy类似,但如果在此列出的单元没有激活,本单元会激活失败,同样在.requires文件夹下创建软链接。 Alias= 设置改单元的别名,可以给systemctl使用,例如上面sshd的开机启动可以使用 systemctl enable ssh.service和systemctl enable sshd.service是一样的 Also= 列在此的单元,会随着本单元一起激活。 [Service] section 以上[Unit],[Install]一般是通用的,[Service]是单独的服务配置一般在[Unit]和[Install]之间,只用来配置服务(.service)。 ...

July 8, 2018 · 2 min · 315 words · Fython