mirror of
https://github.com/f-droid/fdroidserver.git
synced 2025-10-09 02:41:06 +03:00
Move index signing methods into signindex.py
This commit is contained in:
parent
8f96c9da3d
commit
9f765ed6f7
4 changed files with 55 additions and 47 deletions
|
@ -34,7 +34,6 @@ import logging
|
||||||
import hashlib
|
import hashlib
|
||||||
import socket
|
import socket
|
||||||
import base64
|
import base64
|
||||||
import zipfile
|
|
||||||
import xml.etree.ElementTree as XMLElementTree
|
import xml.etree.ElementTree as XMLElementTree
|
||||||
|
|
||||||
from binascii import hexlify
|
from binascii import hexlify
|
||||||
|
@ -390,47 +389,6 @@ def write_password_file(pwtype, password=None):
|
||||||
config[pwtype + 'file'] = filename
|
config[pwtype + 'file'] = filename
|
||||||
|
|
||||||
|
|
||||||
def signjar(jar):
|
|
||||||
'''
|
|
||||||
sign a JAR file with Java's jarsigner.
|
|
||||||
|
|
||||||
This does use old hashing algorithms, i.e. SHA1, but that's not
|
|
||||||
broken yet for file verification. This could be set to SHA256,
|
|
||||||
but then Android < 4.3 would not be able to verify it.
|
|
||||||
https://code.google.com/p/android/issues/detail?id=38321
|
|
||||||
'''
|
|
||||||
args = [config['jarsigner'], '-keystore', config['keystore'],
|
|
||||||
'-storepass:file', config['keystorepassfile'],
|
|
||||||
'-digestalg', 'SHA1', '-sigalg', 'SHA1withRSA',
|
|
||||||
jar, config['repo_keyalias']]
|
|
||||||
if config['keystore'] == 'NONE':
|
|
||||||
args += config['smartcardoptions']
|
|
||||||
else: # smardcards never use -keypass
|
|
||||||
args += ['-keypass:file', config['keypassfile']]
|
|
||||||
p = FDroidPopen(args)
|
|
||||||
if p.returncode != 0:
|
|
||||||
logging.critical("Failed to sign %s!" % jar)
|
|
||||||
sys.exit(1)
|
|
||||||
|
|
||||||
|
|
||||||
def sign_index_v1(repodir, json_name):
|
|
||||||
"""
|
|
||||||
sign index-v1.json to make index-v1.jar
|
|
||||||
|
|
||||||
This is a bit different than index.jar: instead of their being index.xml
|
|
||||||
and index_unsigned.jar, the presense of index-v1.json means that there is
|
|
||||||
unsigned data. That file is then stuck into a jar and signed by the
|
|
||||||
signing process. index-v1.json is never published to the repo. It is
|
|
||||||
included in the binary transparency log, if that is enabled.
|
|
||||||
"""
|
|
||||||
name, ext = get_extension(json_name)
|
|
||||||
index_file = os.path.join(repodir, json_name)
|
|
||||||
jar_file = os.path.join(repodir, name + '.jar')
|
|
||||||
with zipfile.ZipFile(jar_file, 'w', zipfile.ZIP_DEFLATED) as jar:
|
|
||||||
jar.write(index_file, json_name)
|
|
||||||
signjar(jar_file)
|
|
||||||
|
|
||||||
|
|
||||||
def get_local_metadata_files():
|
def get_local_metadata_files():
|
||||||
'''get any metadata files local to an app's source repo
|
'''get any metadata files local to an app's source repo
|
||||||
|
|
||||||
|
|
|
@ -18,6 +18,7 @@
|
||||||
|
|
||||||
import sys
|
import sys
|
||||||
import os
|
import os
|
||||||
|
import zipfile
|
||||||
from argparse import ArgumentParser
|
from argparse import ArgumentParser
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
|
@ -27,6 +28,49 @@ config = None
|
||||||
options = None
|
options = None
|
||||||
|
|
||||||
|
|
||||||
|
def sign_jar(jar):
|
||||||
|
"""
|
||||||
|
Sign a JAR file with Java's jarsigner.
|
||||||
|
|
||||||
|
This method requires a properly initialized config object.
|
||||||
|
|
||||||
|
This does use old hashing algorithms, i.e. SHA1, but that's not
|
||||||
|
broken yet for file verification. This could be set to SHA256,
|
||||||
|
but then Android < 4.3 would not be able to verify it.
|
||||||
|
https://code.google.com/p/android/issues/detail?id=38321
|
||||||
|
"""
|
||||||
|
args = [config['jarsigner'], '-keystore', config['keystore'],
|
||||||
|
'-storepass:file', config['keystorepassfile'],
|
||||||
|
'-digestalg', 'SHA1', '-sigalg', 'SHA1withRSA',
|
||||||
|
jar, config['repo_keyalias']]
|
||||||
|
if config['keystore'] == 'NONE':
|
||||||
|
args += config['smartcardoptions']
|
||||||
|
else: # smardcards never use -keypass
|
||||||
|
args += ['-keypass:file', config['keypassfile']]
|
||||||
|
p = common.FDroidPopen(args)
|
||||||
|
if p.returncode != 0:
|
||||||
|
logging.critical("Failed to sign %s!" % jar)
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
|
||||||
|
def sign_index_v1(repodir, json_name):
|
||||||
|
"""
|
||||||
|
Sign index-v1.json to make index-v1.jar
|
||||||
|
|
||||||
|
This is a bit different than index.jar: instead of their being index.xml
|
||||||
|
and index_unsigned.jar, the presence of index-v1.json means that there is
|
||||||
|
unsigned data. That file is then stuck into a jar and signed by the
|
||||||
|
signing process. index-v1.json is never published to the repo. It is
|
||||||
|
included in the binary transparency log, if that is enabled.
|
||||||
|
"""
|
||||||
|
name, ext = common.get_extension(json_name)
|
||||||
|
index_file = os.path.join(repodir, json_name)
|
||||||
|
jar_file = os.path.join(repodir, name + '.jar')
|
||||||
|
with zipfile.ZipFile(jar_file, 'w', zipfile.ZIP_DEFLATED) as jar:
|
||||||
|
jar.write(index_file, json_name)
|
||||||
|
sign_jar(jar_file)
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
|
|
||||||
global config, options
|
global config, options
|
||||||
|
@ -54,7 +98,7 @@ def main():
|
||||||
|
|
||||||
unsigned = os.path.join(output_dir, 'index_unsigned.jar')
|
unsigned = os.path.join(output_dir, 'index_unsigned.jar')
|
||||||
if os.path.exists(unsigned):
|
if os.path.exists(unsigned):
|
||||||
common.signjar(unsigned)
|
sign_jar(unsigned)
|
||||||
os.rename(unsigned, os.path.join(output_dir, 'index.jar'))
|
os.rename(unsigned, os.path.join(output_dir, 'index.jar'))
|
||||||
logging.info('Signed index in ' + output_dir)
|
logging.info('Signed index in ' + output_dir)
|
||||||
signed += 1
|
signed += 1
|
||||||
|
@ -62,7 +106,7 @@ def main():
|
||||||
json_name = 'index-v1.json'
|
json_name = 'index-v1.json'
|
||||||
index_file = os.path.join(output_dir, json_name)
|
index_file = os.path.join(output_dir, json_name)
|
||||||
if os.path.exists(index_file):
|
if os.path.exists(index_file):
|
||||||
common.sign_index_v1(output_dir, json_name)
|
sign_index_v1(output_dir, json_name)
|
||||||
os.remove(index_file)
|
os.remove(index_file)
|
||||||
logging.info('Signed ' + index_file)
|
logging.info('Signed ' + index_file)
|
||||||
signed += 1
|
signed += 1
|
||||||
|
|
|
@ -45,6 +45,7 @@ from binascii import hexlify, unhexlify
|
||||||
from PIL import Image
|
from PIL import Image
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
|
from . import signindex
|
||||||
from . import common
|
from . import common
|
||||||
from . import metadata
|
from . import metadata
|
||||||
from .common import FDroidPopen, FDroidPopenBytes, SdkToolsPopen
|
from .common import FDroidPopen, FDroidPopenBytes, SdkToolsPopen
|
||||||
|
@ -1374,7 +1375,8 @@ def make_index_v1(apps, packages, repodir, repodict, requestsdict):
|
||||||
if options.nosign:
|
if options.nosign:
|
||||||
logging.debug('index-v1 must have a signature, use `fdroid signindex` to create it!')
|
logging.debug('index-v1 must have a signature, use `fdroid signindex` to create it!')
|
||||||
else:
|
else:
|
||||||
common.sign_index_v1(repodir, json_name)
|
signindex.config = config
|
||||||
|
signindex.sign_index_v1(repodir, json_name)
|
||||||
|
|
||||||
|
|
||||||
def make_index_v0(apps, apks, repodir, repodict, requestsdict):
|
def make_index_v0(apps, apks, repodir, repodict, requestsdict):
|
||||||
|
@ -1626,7 +1628,8 @@ def make_index_v0(apps, apks, repodir, repodict, requestsdict):
|
||||||
if os.path.exists(signed):
|
if os.path.exists(signed):
|
||||||
os.remove(signed)
|
os.remove(signed)
|
||||||
else:
|
else:
|
||||||
common.signjar(signed)
|
signindex.config = config
|
||||||
|
signindex.sign_jar(signed)
|
||||||
|
|
||||||
# Copy the repo icon into the repo directory...
|
# Copy the repo icon into the repo directory...
|
||||||
icon_dir = os.path.join(repodir, 'icons')
|
icon_dir = os.path.join(repodir, 'icons')
|
||||||
|
|
|
@ -12,6 +12,8 @@ import tempfile
|
||||||
import unittest
|
import unittest
|
||||||
from zipfile import ZipFile
|
from zipfile import ZipFile
|
||||||
|
|
||||||
|
import fdroidserver.signindex
|
||||||
|
|
||||||
localmodule = os.path.realpath(
|
localmodule = os.path.realpath(
|
||||||
os.path.join(os.path.dirname(inspect.getfile(inspect.currentframe())), '..'))
|
os.path.join(os.path.dirname(inspect.getfile(inspect.currentframe())), '..'))
|
||||||
print('localmodule: ' + localmodule)
|
print('localmodule: ' + localmodule)
|
||||||
|
@ -163,6 +165,7 @@ class CommonTest(unittest.TestCase):
|
||||||
config = fdroidserver.common.read_config(fdroidserver.common.options)
|
config = fdroidserver.common.read_config(fdroidserver.common.options)
|
||||||
config['jarsigner'] = fdroidserver.common.find_sdk_tools_cmd('jarsigner')
|
config['jarsigner'] = fdroidserver.common.find_sdk_tools_cmd('jarsigner')
|
||||||
fdroidserver.common.config = config
|
fdroidserver.common.config = config
|
||||||
|
fdroidserver.signindex.config = config
|
||||||
|
|
||||||
basedir = os.path.dirname(__file__)
|
basedir = os.path.dirname(__file__)
|
||||||
tmpdir = os.path.join(basedir, '..', '.testfiles')
|
tmpdir = os.path.join(basedir, '..', '.testfiles')
|
||||||
|
@ -174,7 +177,7 @@ class CommonTest(unittest.TestCase):
|
||||||
sourcefile = os.path.join(sourcedir, f)
|
sourcefile = os.path.join(sourcedir, f)
|
||||||
testfile = os.path.join(testsdir, f)
|
testfile = os.path.join(testsdir, f)
|
||||||
shutil.copy(sourcefile, testsdir)
|
shutil.copy(sourcefile, testsdir)
|
||||||
fdroidserver.common.signjar(testfile)
|
fdroidserver.signindex.sign_jar(testfile)
|
||||||
# these should be resigned, and therefore different
|
# these should be resigned, and therefore different
|
||||||
self.assertNotEqual(open(sourcefile, 'rb').read(), open(testfile, 'rb').read())
|
self.assertNotEqual(open(sourcefile, 'rb').read(), open(testfile, 'rb').read())
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue