zerx-lab-pencil-bin
maintainer sec-lab
· 0 votes
· scanned 2026-08-03 00:08:14.047287
LOW
View on AUR ↗
Why flagged
The package downloads a prebuilt binary from the project's official domain (pen.dev), which is a legitimate source for the software; the download is not from a swappable or untrusted host, and the content is a standard proprietary application bundle.
Triggered rules
LOW
AI review downgraded a static finding
llm_review
The static rules flagged this MEDIUM, but an AI model (qwen/qwen3-235b-a22b-2507) reviewed the full PKGBUILD and judged it LOW (confidence 95%): The package downloads a prebuilt binary from the project's official domain (pen.dev), which is a legitimate source for the software; the download is not from a swappable or untrusted host, and the content is a standard proprietary application bundle.
1 higher static finding superseded - not the current verdict (shown for transparency)
MEDIUM
source=() URL on a non-standard host
source_untrusted_domain
One or more source=() URLs point to a host outside the trusted allowlist (github.com, gitlab.com, codeberg.org, pypi.org, …).
-
PKGBUILD:41
source_x86_64=("Pencil-${pkgver}-linux-x64.tar.gz::https://www.pen.dev/download/Pencil-linux-x64.tar.gz")
PKGBUILD
1 offending line(s) highlighted
1
# Maintainer: zero <zero@localhost>
2
# Automatically updated by GitHub Actions
3
4
pkgname=zerx-lab-pencil-bin
5
pkgver=1.2.0
6
pkgrel=1
7
pkgdesc="Pencil - Full canvas design tool with native performance"
8
arch=('x86_64')
9
url="https://www.pen.dev"
10
license=('LicenseRef-proprietary')
11
depends=(
12
'alsa-lib'
13
'at-spi2-core'
14
'cairo'
15
'dbus'
16
'expat'
17
'hicolor-icon-theme'
18
'libcups'
19
'libdrm'
20
'libsecret'
21
'libxcomposite'
22
'libxdamage'
23
'libxext'
24
'libxfixes'
25
'libxkbcommon'
26
'libxrandr'
27
'mesa'
28
'nspr'
29
'nss'
30
'pango'
31
'xdg-utils'
32
)
33
optdepends=(
34
'libappindicator: 系统托盘图标支持'
35
'libayatana-appindicator: 系统托盘图标支持(Ayatana)'
36
)
37
provides=('pencil')
38
conflicts=('pencil')
39
options=('!strip')
40
41
source_x86_64=("Pencil-${pkgver}-linux-x64.tar.gz::https://www.pen.dev/download/Pencil-linux-x64.tar.gz")
42
sha256sums_x86_64=('5cb28d5dcd3825c7f1c8e343706ccf6772f6244cce8e0ab6dea8a5c36933f700')
43
44
# _extract_asar_file: 从 app.asar 中提取指定文件
45
# 用法: _extract_asar_file <asar_path> <内部路径> <输出路径>
46
#
47
# 修复说明: asar 格式的 header 区域采用 Chromium pickle 封装,
48
# 数据区起始位置 = 8 + header_size,需对齐到 4 字节边界。
49
# 旧版代码直接用 f.tell() 获取 header_end,缺少对齐处理,
50
# 导致偏移少 1 字节,提取出的文件前面带有垃圾数据。
51
_extract_asar_file() {
52
python3 - "$1" "$2" "$3" << 'PYEOF'
53
import struct, json, sys
54
55
asar_path, inner_path, out_path = sys.argv[1], sys.argv[2], sys.argv[3]
56
57
with open(asar_path, 'rb') as f:
58
# asar 格式 header 布局(均为 little-endian uint32):
59
# [0:4] pickle_size — 外层 pickle 的数据大小
60
# [4:8] header_size — 内层 header 区域的总大小(含 JSON 长度字段 + JSON 数据 + padding)
61
# [8:12] header_str_sz — header 字符串长度(= json_size + padding)
62
# [12:16] json_size — JSON 字符串的实际长度
63
f.read(4) # pickle_size(未使用)
64
header_size = struct.unpack('<I', f.read(4))[0]
65
f.read(4) # header_str_sz(未使用)
66
json_size = struct.unpack('<I', f.read(4))[0]
67
68
json_data = f.read(json_size)
69
70
# 数据区起始 = 8(前两个 uint32 字段自身)+ header_size
71
# 再向上对齐到 4 字节边界(pickle 对齐要求)
72
data_start = 8 + header_size
73
if data_start % 4 != 0:
74
data_start += 4 - (data_start % 4)
75
76
tree = json.loads(json_data)
77
78
def find_file(node, target, prefix=''):
79
if 'files' not in node:
80
return None
81
for name, child in node['files'].items():
82
path = f'{prefix}/{name}'.lstrip('/')
83
if path == target:
84
return child
85
result = find_file(child, target, path)
86
if result:
87
return result
88
return None
89
90
info = find_file(tree, inner_path)
91
if not info:
92
sys.exit(f'错误: 在 asar 中未找到 {inner_path}')
93
94
offset = int(info['offset'])
95
size = int(info['size'])
96
f.seek(data_start + offset)
97
data = f.read(size)
98
99
with open(out_path, 'wb') as out:
100
out.write(data)
101
PYEOF
102
}
103
104
package() {
105
local _srcdir="Pencil-${pkgver}-linux-x64"
106
local _asar="$srcdir/$_srcdir/resources/app.asar"
107
108
# 安装主程序目录
109
install -d "$pkgdir/opt/pencil"
110
cp -r "$srcdir/$_srcdir/." "$pkgdir/opt/pencil/"
111
112
# chrome-sandbox 需要 setuid root
113
chmod 4755 "$pkgdir/opt/pencil/chrome-sandbox"
114
115
# /usr/bin 启动脚本
116
install -d "$pkgdir/usr/bin"
117
cat > "$pkgdir/usr/bin/pencil" << 'EOF'
118
#!/bin/bash
119
exec /opt/pencil/pencil "$@"
120
EOF
121
chmod 755 "$pkgdir/usr/bin/pencil"
122
123
# 从 app.asar 提取图标(多尺寸)
124
# asar 内可用的图标:
125
# out/assets/512x512.png — 512x512 高分辨率图标
126
# out/editor/images/512x512.png — 同上(编辑器用)
127
# out/editor/images/64x64.png — 64x64 小图标
128
local _icon_512="$srcdir/pencil-512x512.png"
129
local _icon_64="$srcdir/pencil-64x64.png"
130
131
_extract_asar_file "$_asar" "out/assets/512x512.png" "$_icon_512"
132
_extract_asar_file "$_asar" "out/editor/images/64x64.png" "$_icon_64"
133
134
# 验证提取的图标是否为有效 PNG
135
for _icon_file in "$_icon_512" "$_icon_64"; do
136
if ! head -c8 "$_icon_file" | grep -q $'\x89PNG'; then
137
error "图标文件不是有效的 PNG: $_icon_file"
138
return 1
139
fi
140
done
141
142
# 安装多尺寸图标到 hicolor 主题
143
install -Dm644 "$_icon_512" "$pkgdir/usr/share/icons/hicolor/512x512/apps/pencil.png"
144
install -Dm644 "$_icon_64" "$pkgdir/usr/share/icons/hicolor/64x64/apps/pencil.png"
145
146
# 生成 128x128 中间尺寸(如果 ImageMagick 可用)
147
if command -v magick &>/dev/null; then
148
local _icon_128="$srcdir/pencil-128x128.png"
149
magick "$_icon_512" -resize 128x128 "$_icon_128"
150
install -Dm644 "$_icon_128" "$pkgdir/usr/share/icons/hicolor/128x128/apps/pencil.png"
151
elif command -v convert &>/dev/null; then
152
local _icon_128="$srcdir/pencil-128x128.png"
153
convert "$_icon_512" -resize 128x128 "$_icon_128"
154
install -Dm644 "$_icon_128" "$pkgdir/usr/share/icons/hicolor/128x128/apps/pencil.png"
155
fi
156
157
# 同时安装到 pixmaps 作为后备
158
install -Dm644 "$_icon_512" "$pkgdir/usr/share/pixmaps/pencil.png"
159
160
# .desktop 文件
161
# KDE Plasma Wayland 通过 desktopFileName 匹配 .desktop 文件名来查找图标。
162
# Electron 使用 package.json 的 productName("Pencil",大写 P)作为:
163
# - desktopFileName → KDE 用此匹配 .desktop 文件名(区分大小写)
164
# - resourceClass → 即 WM_CLASS / app_id
165
# 因此 .desktop 文件名必须为 Pencil.desktop,StartupWMClass 必须为 Pencil。
166
install -Dm644 /dev/stdin \
167
"$pkgdir/usr/share/applications/Pencil.desktop" << 'EOF'
168
[Desktop Entry]
169
Name=Pencil
170
Comment=Full canvas design tool with native performance
171
Exec=pencil %U
172
Icon=pencil
173
Terminal=false
174
Type=Application
175
Categories=Graphics;Design;
176
MimeType=x-scheme-handler/pencil;
177
StartupWMClass=Pencil
178
StartupNotify=true
179
EOF
180
}
181
Changes since previous scan
--- PKGBUILD @ 2026-07-30 00:17+++ PKGBUILD @ 2026-08-03 00:08@@ -2,11 +2,11 @@ # Automatically updated by GitHub Actions pkgname=zerx-lab-pencil-bin-pkgver=1.1.70+pkgver=1.2.0 pkgrel=1 pkgdesc="Pencil - Full canvas design tool with native performance" arch=('x86_64')-url="https://www.pencil.dev"+url="https://www.pen.dev" license=('LicenseRef-proprietary') depends=( 'alsa-lib'@@ -38,8 +38,8 @@ conflicts=('pencil') options=('!strip') -source_x86_64=("Pencil-${pkgver}-linux-x64.tar.gz::https://www.pencil.dev/download/Pencil-linux-x64.tar.gz")-sha256sums_x86_64=('935a11317389077c7095d89009863f094e67f4b73f62c1dc6c0dbec4e29df408')+source_x86_64=("Pencil-${pkgver}-linux-x64.tar.gz::https://www.pen.dev/download/Pencil-linux-x64.tar.gz")+sha256sums_x86_64=('5cb28d5dcd3825c7f1c8e343706ccf6772f6244cce8e0ab6dea8a5c36933f700') # _extract_asar_file: 从 app.asar 中提取指定文件 # 用法: _extract_asar_file <asar_path> <内部路径> <输出路径>Scan history
| Scanned at (UTC) | Severity | Rules |
|---|---|---|
| 2026-08-03 00:08:14 | LOW | 2 |
| 2026-08-02 00:16:08 | LOW | 2 |
| 2026-08-01 00:11:18 | LOW | 2 |
| 2026-07-31 00:14:10 | LOW | 2 |
| 2026-07-30 03:13:55 | MEDIUM | 1 |
| 2026-07-30 00:17:23 | LOW | 2 |
| 2026-07-29 00:25:53 | LOW | 2 |
| 2026-07-28 00:07:28 | LOW | 2 |
| 2026-07-27 00:24:32 | LOW | 2 |
| 2026-07-26 00:07:32 | LOW | 2 |
| 2026-07-25 00:13:44 | LOW | 2 |
| 2026-07-24 00:02:28 | LOW | 2 |
| 2026-07-23 00:14:47 | LOW | 2 |
| 2026-07-22 00:29:32 | LOW | 2 |
| 2026-07-21 00:24:15 | LOW | 2 |
| 2026-07-20 00:19:49 | LOW | 2 |
| 2026-07-19 00:17:08 | LOW | 2 |
| 2026-07-18 00:14:48 | LOW | 2 |
| 2026-07-17 00:06:16 | LOW | 2 |
| 2026-07-16 00:05:41 | LOW | 2 |