Skip to content

Commit e5cd6de

Browse files
Merge fea0491 into ad9ed73
2 parents ad9ed73 + fea0491 commit e5cd6de

9 files changed

Lines changed: 62 additions & 39 deletions

File tree

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,3 +51,4 @@ source/locale/*/cldr.dic
5151
.venv
5252
nvdaHelper/docs/
5353
*.pfx
54+
appveyor-tools/

appveyor.yml

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,8 @@ branches:
1515

1616
environment:
1717
PY_PYTHON: 3.11-32
18-
secure_authenticode_pass:
19-
secure: Way+hJyhbiLG/cmCo4+dHHzS5DiSvk/45o6frnIQ27GBX6nVDsh7jwQ7fSnqxBRP
18+
apiSigningToken:
19+
secure: 8ARK3NZNRlz8VrhTbpTLP5GMnwbqlUN0DK4SYL4FUYSAAEgXUSB+MBcHHLa6JL9E
2020
secure_ssh_pass:
2121
secure: Iql/RhSathGacONacsyr6gis+rjL75UFZ/R+nPAJpo3asAzQSQQd8hfxq0iv8+Th
2222
mozillaSymsAuthToken:
@@ -54,6 +54,7 @@ build_script:
5454
- ps: |
5555
"BUILD_START, $(Get-Date -Format 'o')"| Out-File ../timing.csv -Append
5656
- ps: appveyor\scripts\setSconsArgs.ps1
57+
- ps: Install-Module -Name SignPath -Force
5758
- scons source %sconsArgs%
5859
- scons %sconsOutTargets% %sconsArgs%
5960
- ps: appveyor\scripts\buildSymbolStore.ps1

appveyor/scripts/decryptFilesForSigning.ps1

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,4 @@
11
if(!$env:APPVEYOR_PULL_REQUEST_NUMBER -and $env:feature_signing) {
2-
openssl enc -d -md sha256 -aes-256-cbc -pbkdf2 -salt -pass pass:$env:secure_authenticode_pass -in appveyor\authenticode.pfx.enc -out appveyor\authenticode.pfx
3-
if($LastExitCode -ne 0) {
4-
$errorCode=$LastExitCode
5-
Add-AppveyorMessage "Unable to decrypt authenticode certificate"
6-
}
72
openssl enc -d -md sha256 -aes-256-cbc -pbkdf2 -salt -pass pass:$env:secure_ssh_pass -in appveyor\ssh_id_rsa.enc -out appveyor\ssh_id_rsa
83
if($LastExitCode -ne 0) {
94
$errorCode=$LastExitCode

appveyor/scripts/setSconsArgs.ps1

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ if ($env:versionType) {
1212
}
1313
$sconsArgs += " publisher=`"$env:scons_publisher`""
1414
if (!$env:APPVEYOR_PULL_REQUEST_NUMBER -and $env:feature_signing) {
15-
$sconsArgs += " certFile=appveyor\authenticode.pfx certTimestampServer=http://timestamp.digicert.com"
15+
$sconsArgs += " apiSigningToken=$env:apiSigningToken"
1616
}
1717
$sconsArgs += " version_build=$env:APPVEYOR_BUILD_NUMBER"
1818
# We use cmd to run scons because PowerShell throws exceptions if warnings get dumped to stderr.

appveyor/scripts/sign.ps1

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
# A part of NonVisual Desktop Access (NVDA)
2+
# Copyright (C) 2010-2024 NV Access Limited
3+
# This file may be used under the terms of the GNU General Public License, version 2 or later.
4+
# For more details see: https://www.gnu.org/licenses/gpl-2.0.html
5+
6+
param(
7+
[string]$ApiToken,
8+
[string]$FileToSign
9+
)
10+
11+
Submit-SigningRequest -ApiToken $ApiToken -InputArtifactPath $FileToSign -OutputArtifactPath $FileToSign -OrganizationId "12147e94-bba9-4fef-b29b-300398e90c5a" -ProjectSlug "NVDA" -SigningPolicySlug "release_signing_policy" -WaitForCompletion -Force

appx/sconscript

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,8 @@ else: # not for submission, just side-loadable
5858
packagePublisherDisplayName=env['publisher']
5959
productName="NVDA Screen Reader (Windows Desktop Bridge Edition)"
6060

61-
signExec=env['signExec'] if env['certFile'] else None
61+
signExec=env['signExec'] if (bool(env['certFile']) ^ bool(env['apiSigningToken'])) else None
62+
6263

6364
# Files from NVDA's distribution that cannot be included in the appx due to policy or security restrictions
6465
excludedDistFiles = [

nvdaHelper/archBuild_sconscript

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ if not env.get('MSVC_VERSION') or tuple(map(int, env.get('MSVC_VERSION').split("
7070
TARGET_ARCH=env['TARGET_ARCH']
7171
debug=env['nvdaHelperDebugFlags']
7272
release=env['release']
73-
signExec=env['signExec'] if env['certFile'] else None
73+
signExec=env['signExec'] if (bool(env['certFile']) ^ bool(env['apiSigningToken'])) else None
7474

7575
#Some defines and includes for the environment
7676
env.Append(

nvdaHelper/liblouis/sconscript

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ louisSourceDir = louisRootDir.Dir("liblouis")
3333
louisTableDir = louisRootDir.Dir("tables")
3434
outDir = sourceDir.Dir("louis")
3535
unitTestTablesDir = env.Dir("#tests/unit/brailleTables")
36-
signExec=env['signExec'] if env['certFile'] else None
36+
signExec=env['signExec'] if (bool(env['certFile']) ^ bool(env['apiSigningToken'])) else None
3737

3838
RE_AC_INIT = re.compile(r"^AC_INIT\(\[(?P<package>.*)\], \[(?P<version>.*)\], \[(?P<bugReport>.*)\], \[(?P<tarName>.*)\], \[(?P<url>.*)\]\)")
3939
def getLouisVersion():

sconstruct

Lines changed: 42 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
# A part of NonVisual Desktop Access (NVDA)
2-
# Copyright (C) 2010-2023 NV Access Limited, James Teh, Michael Curran, Peter Vágner, Joseph Lee,
2+
# Copyright (C) 2010-2024 NV Access Limited, James Teh, Michael Curran, Peter Vágner, Joseph Lee,
33
# Reef Turner, Babbage B.V., Leonard de Ruijter, Łukasz Golonka, Accessolutions, Julien Cochuyt,
44
# Cyrille Bougot
55
# This file may be used under the terms of the GNU General Public License, version 2 or later.
@@ -95,6 +95,7 @@ vars.Add(PathVariable("certFile", "The certificate file with which to sign execu
9595
lambda key, val, env: not val or PathVariable.PathIsFile(key, val, env)))
9696
vars.Add("certPassword", "The password for the private key in the signing certificate", "")
9797
vars.Add("certTimestampServer", "The URL of the timestamping server to use to timestamp authenticode signatures", "")
98+
vars.Add("apiSigningToken", "The API key for the signing service", "")
9899
vars.Add(PathVariable("outputDir", "The directory where the final built archives and such will be placed", "output",PathVariable.PathIsDirCreate))
99100
vars.Add(ListVariable("nvdaHelperDebugFlags", "a list of debugging features you require", 'none', ["debugCRT","RTC","analyze"]))
100101
vars.Add(EnumVariable('nvdaHelperLogLevel','The level of logging you wish to see, lower is more verbose','15',allowed_values=[str(x) for x in range(60)]))
@@ -146,6 +147,7 @@ publisher = env["publisher"]
146147
certFile = env["certFile"]
147148
certPassword = env["certPassword"]
148149
certTimestampServer = env["certTimestampServer"]
150+
apiSigningToken = env["apiSigningToken"]
149151
userDocsDir=Dir('user_docs')
150152
sourceDir = env.Dir("source")
151153
Export('sourceDir')
@@ -165,26 +167,38 @@ Export('outFilePrefix')
165167
outputDir=Dir(env['outputDir'])
166168
Export('outputDir')
167169

168-
# An action to sign an executable with certFile.
169-
# we encrypt with SHA256 as this is the minimum required by the Windows Store for appx packages
170-
signExecCmd = ["signtool", "sign", "/fd", "SHA256", "/f", certFile]
171-
if certPassword:
172-
signExecCmd.extend(("/p", certPassword))
173-
if certTimestampServer:
174-
signExecCmd.extend(("/tr", certTimestampServer, "/td", "SHA256"))
175-
def signExec(target,source,env):
176-
print([str(x) for x in target])
177-
#sys.exit(1)
178-
# #3795: signtool can quite commonly fail with timestamping, so allow it to try up to 3 times with a 1 second delay between each try.
179-
res=0
180-
for count in range(3):
181-
res=env.Execute([signExecCmd+[target[0].abspath]])
182-
if not res:
183-
return 0 # success
184-
time.sleep(1)
185-
return res # failed
186-
#Export via scons environment so other libraries can be signed
187-
env['signExec']=signExec
170+
assert not (apiSigningToken and certFile), "Cannot specify signing with both API token (cloud) and local certificate"
171+
if apiSigningToken:
172+
# Code signing with SignPath HSM
173+
def signExecApi(target, source, env):
174+
# Workaround to skip files that we don't want to sign
175+
if len(target) > 1:
176+
print(f"Too many files passed to signExecApi, skipping {[t.abspath for t in target]}")
177+
return 0
178+
ps_cmd = f"powershell -File appveyor\scripts\sign.ps1 -ApiToken {apiSigningToken} -FileToSign {target[0].abspath}"
179+
return env.Execute(ps_cmd, shell=True)
180+
# Export via scons environment so other libraries can be signed
181+
env["signExec"] = signExecApi
182+
elif certFile:
183+
# Local code signing with a certFile
184+
def signExecCert(target,source,env):
185+
# we encrypt with SHA256 as this is the minimum required by the Windows Store for appx packages
186+
signExecCmd = ["signtool", "sign", "/fd", "SHA256", "/f", certFile]
187+
if certPassword:
188+
signExecCmd.extend(("/p", certPassword))
189+
if certTimestampServer:
190+
signExecCmd.extend(("/tr", certTimestampServer, "/td", "SHA256"))
191+
print([str(x) for x in target])
192+
# #3795: signtool can quite commonly fail with timestamping, so allow it to try up to 3 times with a 1 second delay between each try.
193+
res=0
194+
for count in range(3):
195+
res=env.Execute([signExecCmd+[target[0].abspath]])
196+
if not res:
197+
return 0 # success
198+
time.sleep(1)
199+
return res # failed
200+
#Export via scons environment so other libraries can be signed
201+
env["signExec"] = signExecCert
188202

189203
#architecture-specific environments
190204
archTools=['default','midl','msrpc']
@@ -313,9 +327,9 @@ def NVDADistGenerator(target, source, env, for_signature):
313327
if file.name.endswith(".dll") and file.is_file():
314328
action.append(Copy(target[0], file.path))
315329

316-
if certFile:
330+
if certFile or apiSigningToken:
317331
for prog in "nvda_noUIAccess.exe", "nvda_uiAccess.exe", "nvda_slave.exe":
318-
action.append(lambda target,source,env, progByVal=prog: signExec([target[0].File(progByVal)],source,env))
332+
action.append(lambda target, source, env, progByVal=prog: env['signExec']([target[0].File(progByVal)], source, env))
319333

320334
action.extend((
321335
Delete(buildVersionFn),
@@ -376,10 +390,10 @@ uninstGen = env.Command(File("uninstaller/uninstGen.exe"), "uninstaller/uninst.n
376390
"/DINSTEXE=${TARGET.abspath}",
377391
"$SOURCE"]])
378392
uninstaller=env.Command(uninstFile,uninstGen,[uninstGen])
379-
if certFile:
380-
env.AddPostAction(uninstaller, [signExec])
393+
if certFile or apiSigningToken:
394+
env.AddPostAction(uninstaller, [env['signExec']])
381395

382-
dist = env.NVDADist("dist", [sourceDir,userDocsDir], uiAccess=bool(certFile))
396+
dist = env.NVDADist("dist", [sourceDir,userDocsDir], uiAccess=bool(certFile) or bool(apiSigningToken))
383397
env.Depends(dist,uninstaller)
384398
# dist will always be considered obsolete
385399
AlwaysBuild(dist)
@@ -393,8 +407,8 @@ launcher = env.Command(outputDir.File("%s.exe" % outFilePrefix), ["launcher/nvda
393407
"/DVERSION=$version", '/DPUBLISHER="$publisher"','/DCOPYRIGHT="$copyright"','/DVERSION_YEAR="$version_year"','/DVERSION_MAJOR="$version_major"','/DVERSION_MINOR="$version_minor"','/DVERSION_BUILD="$version_build"',
394408
"/DNVDADistDir=${SOURCES[1].abspath}", "/DLAUNCHEREXE=${TARGET.abspath}",
395409
"$SOURCE"]])
396-
if certFile:
397-
env.AddPostAction(launcher, [signExec])
410+
if certFile or apiSigningToken:
411+
env.AddPostAction(launcher, [env['signExec']])
398412
env.Alias("launcher", launcher)
399413

400414
clientArchive = env.ZipArchive(outputDir.File("%s_controllerClient.zip" % outFilePrefix), clientDir, relativeTo=clientDir)

0 commit comments

Comments
 (0)