unofficial mirror of guix-patches@gnu.org 
 help / color / mirror / code / Atom feed
From: Marius Bakke <marius@gnu.org>
To: 44335@debbugs.gnu.org
Subject: [bug#44335] [PATCH v2 2/3] Add (gnu build chromium-extension).
Date: Mon,  2 Nov 2020 01:22:27 +0100	[thread overview]
Message-ID: <20201102002228.5971-3-marius@gnu.org> (raw)
In-Reply-To: <20201102002228.5971-1-marius@gnu.org>

* gnu/build/chromium-extension.scm: New file.
* gnu/local.mk (GNU_SYSTEM_MODULES): Adjust accordingly.
---
 gnu/build/chromium-extension.scm | 192 +++++++++++++++++++++++++++++++
 gnu/local.mk                     |   1 +
 2 files changed, 193 insertions(+)
 create mode 100644 gnu/build/chromium-extension.scm

diff --git a/gnu/build/chromium-extension.scm b/gnu/build/chromium-extension.scm
new file mode 100644
index 0000000000..35f49d788c
--- /dev/null
+++ b/gnu/build/chromium-extension.scm
@@ -0,0 +1,192 @@
+;;; GNU Guix --- Functional package management for GNU
+;;; Copyright © 2020 Marius Bakke <marius@gnu.org>
+;;;
+;;; This file is part of GNU Guix.
+;;;
+;;; GNU Guix is free software; you can redistribute it and/or modify it
+;;; under the terms of the GNU General Public License as published by
+;;; the Free Software Foundation; either version 3 of the License, or (at
+;;; your option) any later version.
+;;;
+;;; GNU Guix is distributed in the hope that it will be useful, but
+;;; WITHOUT ANY WARRANTY; without even the implied warranty of
+;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;;; GNU General Public License for more details.
+;;;
+;;; You should have received a copy of the GNU General Public License
+;;; along with GNU Guix.  If not, see <http://www.gnu.org/licenses/>.
+
+(define-module (gnu build chromium-extension)
+  #:use-module (gcrypt base16)
+  #:use-module ((gcrypt hash) #:prefix hash:)
+  #:use-module (ice-9 iconv)
+  #:use-module (guix gexp)
+  #:use-module (guix packages)
+  #:use-module (gnu packages base)
+  #:use-module (gnu packages check)
+  #:use-module (gnu packages chromium)
+  #:use-module (gnu packages gnupg)
+  #:use-module (gnu packages tls)
+  #:use-module (gnu packages xorg)
+  #:use-module (guix build-system trivial)
+  #:export (make-chromium-extension))
+
+;;; Commentary:
+;;;
+;;; Tools to deal with Chromium extensions.
+;;;
+;;; Code:
+
+(define (make-signing-key seed)
+  "Return a derivation for a deterministic PKCS #8 private key using SEED."
+
+  (define sha256sum
+    (bytevector->base16-string (hash:sha256 (string->bytevector seed "UTF-8"))))
+
+  ;; certtool.c wants a 56 byte seed for a 2048 bit key.
+  (define size 2048)
+  (define normalized-seed (string-take sha256sum 56))
+
+  (computed-file (string-append seed "-signing-key.pem")
+                 #~(system* #$(file-append gnutls "/bin/certtool")
+                            "--generate-privkey"
+                            "--key-type=rsa"
+                            "--pkcs8"
+                            ;; Use the provable FIPS-PUB186-4 algorithm for
+                            ;; deterministic results.
+                            "--provable"
+                            "--password="
+                            "--no-text"
+                            (string-append "--bits=" #$(number->string size))
+                            (string-append "--seed=" #$normalized-seed)
+                            "--outfile" #$output)
+                 #:local-build? #t))
+
+(define* (make-crx package+output signing-key)
+  "Create a signed \".crx\" file from the unpacked Chromium extension residing
+in PACKAGE+OUTPUT, a (list package output) pair.  The extension will be signed
+with SIGNING-KEY."
+  (with-imported-modules '((guix build utils))
+    (computed-file
+     "chromium-extension.crx"
+     #~(begin
+         ;; This is not great.  We pull Xorg and Chromium just to Zip and
+         ;; sign an extension.  This should be implemented with something
+         ;; lighter.  (TODO: where is the documentation..?)
+         (use-modules (guix build utils))
+         (let ((chromium #$(file-append ungoogled-chromium "/bin/chromium"))
+               (xvfb #$(file-append xorg-server "/bin/Xvfb"))
+               (packdir "/tmp/extension"))
+           (mkdir-p (dirname packdir))
+           (copy-recursively (ungexp (car package+output) (cadr package+output))
+                             packdir)
+           (system (string-append xvfb " :1 &"))
+           (setenv "DISPLAY" ":1")
+           (sleep 2)                    ;give Xorg some time to initialize...
+           ;; Chromium stores the current time in the .crx Zip archive.
+           ;; Sidestep that by using "faketime" for determinism.
+           ;; FIXME (core-updates): faketime is missing an absolute reference
+           ;; to 'date', hence the need to set PATH.
+           (setenv "PATH" #$(file-append coreutils "/bin"))
+           (invoke #$(file-append libfaketime "/bin/faketime")
+                   "2000-01-01 00:00:00"
+                   chromium
+                   "--user-data-dir=/tmp/signing-profile"
+                   (string-append "--pack-extension=" packdir)
+                   (string-append "--pack-extension-key=" #$signing-key))
+           (copy-file (string-append packdir ".crx") #$output)))
+     #:local-build? #t)))
+
+(define* (crx->chromium-json crx version)
+  "Return a derivation that creates a Chromium JSON settings file for the
+unpacked extension residing in output PACKAGE-OUTPUT of PACKAGE."
+  (computed-file "extension.json"
+                 #~(call-with-output-file #$output
+                     (lambda (port)
+                       ;; Documentation for the JSON format can be found in
+                       ;; extensions/common/extension.h and
+                       ;; chrome/browser/extensions/external_provider_impl.cc.
+                       (format port "
+{
+  \"external_crx\": \"~a\",
+  \"external_version\": \"~a\"
+}
+"
+                               #$crx #$version)))
+                 #:local-build? #t))
+
+
+(define (signing-key->public-der key)
+  "Return a derivation for a file containing the public key of KEY in DER
+format."
+  (computed-file "der"
+                 #~(system* #$(file-append gnutls "/bin/certtool")
+                            "--load-privkey" #$key
+                            "--pubkey-info"
+                            "--outfile" #$output
+                            "--outder")
+                 #:local-build? #t))
+
+(define (chromium-json->profile-object json signing-key)
+  "Return a derivation that installs JSON to the directory searched by
+Chromium, using a file name (aka extension ID) derived from SIGNING-KEY."
+  (define der (signing-key->public-der signing-key))
+
+  (with-extensions (list guile-gcrypt)
+    (with-imported-modules '((guix build utils))
+      (computed-file
+       "chromium-extension.json"
+       #~(begin
+           (use-modules (guix build utils)
+                        (gcrypt base16)
+                        (gcrypt hash))
+           (define (base16-string->chromium-base16 str)
+             ;; Translate STR, a hexadecimal string, to a Chromium-style
+             ;; representation using the letters a-p (where a=0, p=15).
+             (define s1 "0123456789abcdef")
+             (define s2 "abcdefghijklmnop")
+             (let loop ((chars (string->list str))
+                        (converted '()))
+               (if (null? chars)
+                   (list->string (reverse converted))
+                   (loop (cdr chars) (cons (string-ref
+                                            s2 (string-index s1 (car chars)))
+                                           converted)))))
+
+           (let* ((checksum (bytevector->base16-string (file-sha256 #$der)))
+                  (file-name (base16-string->chromium-base16
+                              (string-take checksum 32)))
+                  (extension-directory (string-append #$output
+                                                      "/share/chromium/extensions")))
+             (mkdir-p extension-directory)
+             (symlink #$json (string-append extension-directory "/"
+                                            file-name ".json"))))
+       #:local-build? #t))))
+
+(define* (make-chromium-extension p #:optional (output "out"))
+  "Create a Chromium extension from package P and return a package that,
+when installed, will make the extension contained in P available as a
+Chromium browser extension.  OUTPUT specifies which output of P to use."
+  (let* ((pname (package-name p))
+         (version (package-version p))
+         (signing-key (make-signing-key pname)))
+    (package
+      (inherit p)
+      (name (string-append pname "-chromium"))
+      (build-system trivial-build-system)
+      (native-inputs '())
+      (inputs
+       `(("extension" ,(chromium-json->profile-object
+                        (crx->chromium-json (make-crx (list p output)
+                                                      signing-key)
+                                            version)
+                        signing-key))))
+      (propagated-inputs '())
+      (outputs '("out"))
+      (arguments
+       '(#:modules ((guix build utils))
+         #:builder
+         (begin
+           (use-modules (guix build utils))
+           (copy-recursively (assoc-ref %build-inputs "extension")
+                             (assoc-ref %outputs "out"))))))))
diff --git a/gnu/local.mk b/gnu/local.mk
index 51550e80cb..e847f8c16a 100644
--- a/gnu/local.mk
+++ b/gnu/local.mk
@@ -657,6 +657,7 @@ GNU_SYSTEM_MODULES =				\
   %D%/build/accounts.scm			\
   %D%/build/activation.scm			\
   %D%/build/bootloader.scm			\
+  %D%/build/chromium-extension.scm		\
   %D%/build/cross-toolchain.scm			\
   %D%/build/image.scm				\
   %D%/build/file-systems.scm			\
-- 
2.28.0





  parent reply	other threads:[~2020-11-02  0:23 UTC|newest]

Thread overview: 11+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2020-10-30 18:29 [bug#44335] [PATCH 0/2] Install Chromium extensions with Guix! Marius Bakke
2020-10-30 18:32 ` [bug#44335] [PATCH 1/2] gnu: ungoogled-chromium: Add search path for installed extensions Marius Bakke
2020-10-30 18:32   ` [bug#44335] [PATCH 2/2] gnu: Add ublock-origin-chromium Marius Bakke
2020-11-02  0:22 ` [bug#44335] [PATCH v2 0/3] Install Chromium extensions with Guix! Marius Bakke
2020-11-02  0:22   ` [bug#44335] [PATCH v2 1/3] gnu: ungoogled-chromium: Add search path for installed extensions Marius Bakke
2020-11-02  0:22   ` Marius Bakke [this message]
2020-11-02  0:28     ` [bug#44335] [PATCH v2 2/3] Add (gnu build chromium-extension) Marius Bakke
2020-11-02  0:22   ` [bug#44335] [PATCH v2 3/3] gnu: Add ublock-origin-chromium Marius Bakke
2020-11-02  0:55   ` [bug#44335] [PATCH v2 0/3] Install Chromium extensions with Guix! Leo Famulari
2020-11-08 17:38     ` bug#44335: " Marius Bakke
2020-11-08 17:46       ` [bug#44335] " Leo Famulari

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

  List information: https://guix.gnu.org/

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20201102002228.5971-3-marius@gnu.org \
    --to=marius@gnu.org \
    --cc=44335@debbugs.gnu.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
Code repositories for project(s) associated with this public inbox

	https://git.savannah.gnu.org/cgit/guix.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).