Skip to content

Commit

Permalink
helper: Use pyscreenshot for cross-platform QR capture
Browse files Browse the repository at this point in the history
pyscreenshot supports capturing screenshots via numerous backends
and can automatically select the best one depending on platform.
This enables capturing of the QR code on wayland-based desktops
while maintaining support for Windows and X11
  • Loading branch information
evan-a-a committed Apr 24, 2023
1 parent f5100e1 commit c3dc2d0
Show file tree
Hide file tree
Showing 4 changed files with 63 additions and 63 deletions.
2 changes: 1 addition & 1 deletion build-helper.sh
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ VENV="../$OUTPUT/helper-license-venv"
rm -rf $VENV
poetry run python -m venv $VENV
$VENV/bin/pip install --upgrade pip wheel
$VENV/bin/pip install dist/authenticator_helper-0.1.0-py3-none-any.whl pip-licenses
$VENV/bin/pip install dist/authenticator_helper-0.2.0-py3-none-any.whl pip-licenses
$VENV/bin/pip-licenses --format=json --no-license-path --with-license-file --ignore-packages authenticator-helper zxing-cpp --output-file ../assets/licenses/helper.json
cd ..

Expand Down
56 changes: 7 additions & 49 deletions helper/helper/qr.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,66 +12,24 @@
# See the License for the specific language governing permissions and
# limitations under the License.

import mss
import zxingcpp
import base64
import io
import os
import sys
import subprocess # nosec
import tempfile
from mss.exception import ScreenShotError
import pyscreenshot as ImageGrab
from pyscreenshot import FailedBackendError
from PIL import Image
import numpy.core.multiarray # noqa


def _capture_screen():
try:
with mss.mss() as sct:
monitor = sct.monitors[0] # 0 is the special "all monitors" value.
sct_img = sct.grab(monitor) # mss format
return Image.frombytes("RGB", sct_img.size, sct_img.bgra, "raw", "BGRX")
except ScreenShotError:
# One common error is that mss doesn't work with Wayland
if sys.platform.startswith("linux"):
# Try calling screenshot tools, with original library path
env = dict(os.environ)
lp = env.get("LD_LIBRARY_PATH_ORIG")
if lp is not None:
env["LD_LIBRARY_PATH"] = lp
else:
env.pop("LD_LIBRARY_PATH", None)
fd, fname = tempfile.mkstemp(suffix=".png")

try:
# Try using gnome-screenshot
rc = subprocess.call( # nosec
["gnome-screenshot", "-f", fname], env=env
)
if rc == 0:
return Image.open(fname)
except FileNotFoundError:
# Try using spectacle (KDE)
try:
rc = subprocess.call( # nosec
["spectacle", "-b", "-n", "-o", fname], env=env
)
if rc == 0:
return Image.open(fname)
except FileNotFoundError:
pass # Fall through to ValueError
finally:
os.unlink(fname)
raise ValueError("Unable to capture screenshot")


def scan_qr(image_data=None):
img = None
if image_data:
msg = base64.b64decode(image_data)
buf = io.BytesIO(msg)
img = Image.open(buf)
else:
img = _capture_screen()
try:
img = ImageGrab.grab()
except FailedBackendError:
raise ValueError("Unable to capture screenshot")

result = zxingcpp.read_barcode(img)
if result and result.valid:
Expand Down
64 changes: 53 additions & 11 deletions helper/poetry.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions helper/pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[tool.poetry]
name = "authenticator-helper"
version = "0.1.0"
version = "0.2.0"
description = "Yubico Authenticator Helper"
authors = ["Dain Nilsson <[email protected]>"]
packages = [
Expand All @@ -11,9 +11,9 @@ packages = [
[tool.poetry.dependencies]
python = "^3.8"
yubikey-manager = "5.1.0"
mss = "^8.0.3"
zxing-cpp = "^2.0.0"
Pillow = "^9.5.0"
pyscreenshot = "^3.1"

[tool.poetry.dev-dependencies]
pyinstaller = {version = "^5.10.1", python = "<3.12"}
Expand Down

0 comments on commit c3dc2d0

Please sign in to comment.