How to create chrome crx file programmatically (preferably in java)?
Asked Answered
J

4

17

I want to create chrome extension crx file programatically (not using chrome.exe, because it opens new chrome window). So what are the alternatives for same ? My preference is java, but if its possible in other language then also I am okay.

Jaleesa answered 7/7, 2010 at 16:3 Comment(1)
I had a similar problem , here is the solution: #24661667Wolffish
C
18

There is a variety of utilities to do this, in various languages (albeit; they are mostly shell/scripting languages)

I cannot post the links to all of them, because I am a new stackoverflow user - I can only post 1 link, so I created a page which lists them all - including the one C one I speak about below - http://curetheitch.com/projects/buildcrx/6/

Anyway, I spent a few hours and put together a version in C which runs on Windows or Linux, as the other solutions require installation of a scripting language or shell (i.e. python, ruby, bash, etc.) and OpenSSL. The utility I wrote has OpenSSL statically linked so there are no interpreter or library requirements.

The repository is hosted on github, but the link above has a list of my utility and other peoples solutions.

Nothing listed for Java, which was your preference, but hopefully that helps!

Copenhagen answered 11/10, 2010 at 17:0 Comment(2)
I know this is old, but this helped me a lot!Preparation
Can you update your answer with the actual links seeing as you are no longer a new user?Manicdepressive
W
29

As kylehuff stated, there are external tools that you could use. But you can always use the command line from Google Chrome to do that which is cross platform (Linux / Windows / Mac).

chrome.exe --pack-extension=[extension_path] --pack-extension-key=[extension_key]

--pack-extension is:

Package an extension to a .crx installable file from a given directory.

--pack-extension-key is:

Optional PEM private key is to use in signing packaged .crx.

The above does not run Google Chrome, it is just command line packing using Chromium's core crx algorithm that they use internally.

Wort answered 11/10, 2010 at 18:22 Comment(4)
If you also use the --no-message-box option the process will be completely silent, suitable for use in a script.Javelin
I've got a return code of 21 but no crx file around.Superabound
Could you tell me where does the output file come?Blondellblondelle
You need to include the version in [extension_path]. The file is generated in the top level directory. For example the command chrome --pack-extension=/path/to/chrome-profile/Extensions/pehaalcefcjfccdpbckoablngfkfgfgj/1.1_0 generates the file at /path/to/chrome-profile/Extensions/pehaalcefcjfccdpbckoablngfkfgfgj/1.1_0.crxMonolayer
C
18

There is a variety of utilities to do this, in various languages (albeit; they are mostly shell/scripting languages)

I cannot post the links to all of them, because I am a new stackoverflow user - I can only post 1 link, so I created a page which lists them all - including the one C one I speak about below - http://curetheitch.com/projects/buildcrx/6/

Anyway, I spent a few hours and put together a version in C which runs on Windows or Linux, as the other solutions require installation of a scripting language or shell (i.e. python, ruby, bash, etc.) and OpenSSL. The utility I wrote has OpenSSL statically linked so there are no interpreter or library requirements.

The repository is hosted on github, but the link above has a list of my utility and other peoples solutions.

Nothing listed for Java, which was your preference, but hopefully that helps!

Copenhagen answered 11/10, 2010 at 17:0 Comment(2)
I know this is old, but this helped me a lot!Preparation
Can you update your answer with the actual links seeing as you are no longer a new user?Manicdepressive
W
3
//Method to generate .crx. signature


import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.SecureRandom;
import java.security.Signature;
    //@param : extenstionContents  is your zip file , 
    //@returns :  byte[] of the signature , use ByteBuffer to merge them and you have your   
    // .crx
    public static byte[] generateCrxHeader(byte[] extensionContents) throws Exception {
        KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA");      
        SecureRandom random = new SecureRandom();
        keyGen.initialize(1024, random);        

        KeyPair pair = keyGen.generateKeyPair();

        Signature sigInstance = Signature.getInstance("SHA1withRSA");
        sigInstance.initSign(pair.getPrivate());
        sigInstance.update(extensionContents);
        byte [] signature = sigInstance.sign();
        byte [] subjectPublicKeyInfo = pair.getPublic().getEncoded();
        final int headerLength = 4 + 4 + 4 + 4 + subjectPublicKeyInfo.length + signature.length;
        ByteBuffer headerBuf = ByteBuffer.allocate(headerLength);
        headerBuf.order(ByteOrder.LITTLE_ENDIAN);
        headerBuf.put(new byte[]{0x43,0x72,0x32,0x34}); // Magic number
        headerBuf.putInt(2); // Version
        headerBuf.putInt(subjectPublicKeyInfo.length); // public key length
        headerBuf.putInt(signature.length); // signature length
        headerBuf.put(subjectPublicKeyInfo);
        headerBuf.put(signature);
        final byte [] header = headerBuf.array();
        return header;
    }
Wolffish answered 11/7, 2014 at 3:34 Comment(2)
I thought signature and public key are optional by crx, but not. That was missing puzzle for my solution.Protochordate
unfortunately, version 2 crx is no longer supportedAngling
S
0

I needed to do this in Ruby. JavaHead's answer looks nice for Java for CRX2. The current format is CRX v3 and header is protobuf based. I wrote a blog for packing an extension with Ruby. There is also a python project from another author.

I'll paste Ruby version of CRX2 and CRX3 methods for packing extensions for a reference here. For complete code see my blog.

So CRX3 method:

 def self.header_v3_extension(zipdata, key: nil)
    key ||= OpenSSL::PKey::RSA.generate(2048)

    digest = OpenSSL::Digest.new('sha256')
    signed_data = Crx_file::SignedData.new
    signed_data.crx_id = digest.digest(key.public_key.to_der)[0...16]
    signed_data = signed_data.encode

    signature_data = String.new(encoding: "ASCII-8BIT")
    signature_data << "CRX3 SignedData\00"
    signature_data << [ signed_data.size ].pack("V")
    signature_data << signed_data
    signature_data << zipdata

    signature = key.sign(digest, signature_data)

    proof = Crx_file::AsymmetricKeyProof.new
    proof.public_key = key.public_key.to_der
    proof.signature = signature

    header_struct = Crx_file::CrxFileHeader.new
    header_struct.sha256_with_rsa = [proof]
    header_struct.signed_header_data = signed_data
    header_struct = header_struct.encode

    header = String.new(encoding: "ASCII-8BIT")
    header << "Cr24"
    header << [ 3 ].pack("V") # version
    header << [ header_struct.size ].pack("V")
    header << header_struct

    return header
  end

And for historic purposes (this one verified) CRX2:

  # @note original crx2 format description https://web.archive.org/web/20180114090616/https://developer.chrome.com/extensions/crx
  def self.header_v2_extension(zipdata, key: nil)
    key ||= OpenSSL::PKey::RSA.generate(2048)
    digest = OpenSSL::Digest.new('sha1')
    header = String.new(encoding: "ASCII-8BIT")

    signature = key.sign(digest, zipdata)
    signature_length = signature.length
    pubkey_length = key.public_key.to_der.length

    header << "Cr24"
    header << [ 2 ].pack("V") # version
    header << [ pubkey_length ].pack("V")
    header << [ signature_length ].pack("V")
    header << key.public_key.to_der
    header << signature

    return header
  end

I have used the excellent service crx-checker to validate both - v2 and v3 extension packing. Where I'm getting the expected RSASSA-PKCS1-v1_5 signature marked (Signature OK) (Developer Signature).

The extension will fail to load with CRX_REQUIRED_PROOF_MISSING if you try to add to your browser from URL because it will be lacking Google signature. But it will be loaded fine by Selenium when running test. To load normally you need to publish on web store.

Smoothbore answered 23/11, 2019 at 15:21 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.