Index: client/pkgd.eagle
==================================================================
--- client/pkgd.eagle
+++ client/pkgd.eagle
@@ -114,18 +114,22 @@
variable persistentDirectory
variable quiet
if {$persistent} then {
set downloadRootDirectory [file join $persistentDirectory]
- } elseif {[info exists ::env(PKGD_TEMP)]} then {
- set downloadRootDirectory [file join $::env(PKGD_TEMP) pkgr]
- } elseif {[info exists ::env(TEMP)]} then {
- set downloadRootDirectory [file join $::env(TEMP) pkgr]
- } elseif {[info exists ::env(TMP)]} then {
- set downloadRootDirectory [file join $::env(TMP) pkgr]
} else {
- error "please set PKGD_TEMP (via environment) to temporary directory"
+ global env
+
+ if {[info exists env(PKGD_TEMP)]} then {
+ set downloadRootDirectory [file join $env(PKGD_TEMP) pkgr]
+ } elseif {[info exists env(TEMP)]} then {
+ set downloadRootDirectory [file join $env(TEMP) pkgr]
+ } elseif {[info exists env(TMP)]} then {
+ set downloadRootDirectory [file join $env(TMP) pkgr]
+ } else {
+ error "please set PKGD_TEMP (via environment) to temporary directory"
+ }
}
set downloadDirectories [list]
foreach fileName $fileNames {
Index: client/pkgd.eagle.harpy
==================================================================
--- client/pkgd.eagle.harpy
+++ client/pkgd.eagle.harpy
@@ -19,32 +19,32 @@
None
Mistachkin Systems
- 06b76c33-0e3b-4120-8142-0053f4d17521
+ 36e6e8e4-39ac-4f29-928e-5c10e32cb1eb
SHA512
Script
- 2016-08-16T02:50:58.2761250Z
+ 2016-08-16T23:11:46.2517109Z
-1.00:00:00
0x2c322765603b5278
- VsQxIv0pQbKwapByuSpDz4HcbTBrr+UtPdW8V2nlF/7x5yjzxXGcBqH/Ub+zYYLGUvDgPLKW2nST
- UlGW+GRnKOJ4rvVytLL4IY415E4p86qUL5l3mgeY++OyYHSDgbBEEW1SlbU+l+0NaZvH2zFWBkMe
- mDbEsuGRJpGvXm1sJfZP15UTnoNNJ/446isFNRvPCV9gTp7/1GFs+w9943iXRYAQi9hN2fSSgotc
- FapDXfkspC0arL4jFCpo0WrY2Pdtc//avflPm8OR0dZeZFNG1fLQHMEvWpq+CwY/KHZ3xMEUDIb5
- +i+ziLYO+3nNtXuaxzEnTgajelG0qPMZceOEF0Esz3ePOMKNhl7N503y4rm8U/IRGVTkPeCDwjHW
- mmX5ORiHt/QM8asUVfl+Mh1bmy6ty6Lk3xX8hqV3ZsE85bVSihrFirXXEcHMW6CZY3sC0I5Mpn0D
- V5u9MzrI6iE6oBsme86/WMsBq93wHweIqV5RNxiYG+Cdyb3E4yCMh2Kx5cHegiFA0oTbUy+IGp5Q
- 3n5pA0lGwhuWUrME9cVj6b/+ZMMdlwhMWQSpZE6GdDf5wJeUY4iK9IIqUADHnrqOs3chgUJgYrjo
- b88nXT/2AFVZqWe9R+ecln6e3FjFCNfyLqNpfo0miOXYxj52m2dWNOlOYVZsjyfxFm2DjYTwf0Zr
- VJJWF1ojfah1D9Ys1HxpuvbQkKAZD03lJfp5rLStD2vo3o8dyujZtoQ09nRzStSOuflBFd+hEmzh
- 4/nrkRs8+szY0MMSrwZSTlOn9WwvEvtDEzHs+9sLftfjg3FO/QLTV/ZTiROKZn1kTeLhczNRTpDy
- 6HXUR4rxqrvQ9hT8fgRe9O3uEvazjktkoPkpNcTSsC0Hdwf+thuaGZiqx9dHebIzrLsBFz9gQdJC
- LCMwDeNyOykj10vV6GIfUjLCysJqdBPfdyBDvRbd6gXhkKnzTn5M1xiCAdnRNnXKNbXIzNIz8P+w
- z3Ygzy0JBaZ5bM8lADfY4A9kPSAqab07w/Rln/qOcfxteap/qwLnXmjJ1fyBorozisJ82Ldi+4un
- jFbddGkFyOamC/gLVI2JyyiBdb8HOUkmSQOu7/2BpdnOPtLA8udhyDVI8g83EUeDwGcRXJCzWH8B
- 1fhfdycdMGrFkg5OHQHGo0ESod1lMwrr95LzEMB1StUx/HBVBZuBS0eJc3FzAVcDClgwCvLY6Ahw
- 0sp5yaO+zd0Rcuq3DQ+RLwiQmHBO+jFjCScOw9RAEU+MTL5hbEv6IloIOLpsVcI6fmBncfRBp1Nw
- 7NpQxGD2cQYVUHHbMO1opK69LFlyfCzaleKSHRo2uugSCaJI883TE0T5ErCBwYtnqYVPuOL2Wg==
+ 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
Index: client/pkgr.eagle
==================================================================
--- client/pkgr.eagle
+++ client/pkgr.eagle
@@ -30,16 +30,20 @@
package require Eagle.Library
proc stringIsList { value } {
if {[isEagle]} then {
return [string is list $value]
- } elseif {[info exists ::tcl_version] && $::tcl_version >= 8.5} then {
- return [string is list $value]
- } elseif {[catch {llength $value}] == 0} then {
- return true
} else {
- return false
+ global tcl_version
+
+ if {[info exists tcl_version] && $tcl_version >= 8.5} then {
+ return [string is list $value]
+ } elseif {[catch {llength $value}] == 0} then {
+ return true
+ } else {
+ return false
+ }
}
}
proc isHarpyCertificate { value } {
if {[string length $value] == 0 || [string first [string trim {
@@ -58,10 +62,41 @@
return true
} else {
return false
}
}
+
+ proc getFileTempName {} {
+ if {[isEagle]} then {
+ return [file tempname]
+ } else {
+ global env
+
+ if {[info exists env(PKGR_TEMP)]} then {
+ set directory $env(PKGD_TEMP)
+ } elseif {[info exists env(TEMP)]} then {
+ set directory $env(TEMP)
+ } elseif {[info exists env(TMP)]} then {
+ set directory $env(TMP)
+ } else {
+ error "please set PKGR_TEMP (via environment) to temporary directory"
+ }
+
+ set counter [expr {[pid] ^ int(rand() * 0xFFFF)}]
+
+ while {1} {
+ set fileNameOnly [format tcl%04X.tmp $counter]
+ set fileName [file join $directory $fileNameOnly]
+
+ if {![file exists $fileName]} then {
+ return $fileName
+ }
+
+ incr counter
+ }
+ }
+ }
proc verifyPgpSignature { fileName } {
variable pgpCommand
if {[isEagle]} then {
@@ -349,18 +384,21 @@
[getLookupVarNamePrefix] eagleHasSecurity_ [getLookupVarNameSuffix]]
set newProcName(2) [appendArgs \
[getLookupVarNamePrefix] tclMustBeReady_ [getLookupVarNameSuffix]]
+ set newProcName(3) [appendArgs \
+ [getLookupVarNamePrefix] getFileTempName_ [getLookupVarNameSuffix]]
+
#
# NOTE: Create the Eagle script block that will be used to securely
# evaluate a signed package script. This must be evaluated in
# Eagle because it uses several plugins only available there.
#
set script(outer) [string map [list \
%metadata% $newVarName %eagleHasSecurity% $newProcName(1) \
- %tclMustBeReady% $newProcName(2)] {
+ %tclMustBeReady% $newProcName(2) %getFileTempName% $newProcName(3)] {
try {
#
# NOTE: If there is no package ifneeded script, there is nothing we
# can do here.
#
@@ -376,21 +414,21 @@
try {
#
# NOTE: Figure out temporary file name for the downloaded script
# and its associated script certificate.
#
- set fileName(1) [file tempname]
+ set fileName(1) [{%getFileTempName%}]
set fileName(2) [appendArgs $fileName(1) .harpy]
try {
#
- # NOTE: Write the downloaded script to a temporary file.
+ # NOTE: Write downloaded script to a temporary file.
#
writeFile $fileName(1) ${%metadata%(ifNeeded)}
#
- # NOTE: Write the downloaded script certificateto a temporary
+ # NOTE: Write downloaded script certificate to a temporary
# file.
#
if {[string length ${%metadata%(certificate)}] > 0} then {
writeFile $fileName(2) ${%metadata%(certificate)}
}
@@ -436,12 +474,12 @@
error "unsupported language"
}
}
} finally {
#
- # NOTE: Delete any temporary files that we created during the
- # signed script evaluation.
+ # NOTE: Delete the temporary files that we created for the
+ # signed script verification.
#
if {[string length $fileName(2)] > 0 && \
[file exists $fileName(2)]} then {
catch {file delete $fileName(2)}
unset -nocomplain fileName(2)
@@ -460,10 +498,11 @@
if {!$savedSecurity} then {source disableSecurity}
unset -nocomplain savedSecurity
}
}
} finally {
+ rename {%getFileTempName%} ""
rename {%tclMustBeReady%} ""
rename {%eagleHasSecurity%} ""
unset -nocomplain {%metadata%}
}
@@ -480,10 +519,13 @@
[namespace current] ::eagleHasSecurity]]
proc $newProcName(2) {} [info body [appendArgs \
[namespace current] ::tclMustBeReady]]
+ proc $newProcName(3) {} [info body [appendArgs \
+ [namespace current] ::getFileTempName]]
+
return [eval $script(outer)]
} else {
eagleMustBeReady
eagle [list array set $newVarName [array get metadata]]
@@ -492,14 +534,102 @@
[namespace current] ::eagleHasSecurity]]]
eagle [list proc $newProcName(2) {} [info body [appendArgs \
[namespace current] ::tclMustBeReady]]]
+ eagle [list proc $newProcName(3) {} [info body [appendArgs \
+ [namespace current] ::getFileTempName]]]
+
return [eagle $script(outer)]
}
} elseif {[isPgpSignature $metadata(certificate)]} then {
- error "not yet implemented"
+ #
+ # NOTE: If there is no package ifneeded script, there is nothing we
+ # can do here.
+ #
+ if {[string length $metadata(ifNeeded)] > 0} then {
+ #
+ # NOTE: Figure out temporary file name for the downloaded script
+ # and its associated PGP signature.
+ #
+ set fileName(1) [getFileTempName]
+ set fileName(2) [appendArgs $fileName(1) .asc]
+
+ #
+ # NOTE: Write downloaded script to a temporary file.
+ #
+ writeFile $fileName(1) $metadata(ifNeeded)
+
+ #
+ # NOTE: Write downloaded script PGP signature a temporary file.
+ #
+ if {[string length $metadata(certificate)] > 0} then {
+ writeFile $fileName(2) $metadata(certificate)
+ }
+
+ #
+ # NOTE: Attempt to verify the PGP signature for the package script.
+ # If this fails, raise an error.
+ #
+ if {![verifyPgpSignature $fileName(2)]} then {
+ error [appendArgs \
+ "couldn't read file \"" $fileName(1) "\": bad PGP signature"]
+ }
+
+ #
+ # NOTE: Delete the temporary files that we created for the PGP
+ # signature verification.
+ #
+ if {[string length $fileName(2)] > 0 && \
+ [file exists $fileName(2)]} then {
+ catch {file delete $fileName(2)}
+ unset -nocomplain fileName(2)
+ }
+
+ if {[string length $fileName(1)] > 0 && \
+ [file exists $fileName(1)]} then {
+ catch {file delete $fileName(1)}
+ unset -nocomplain fileName(1)
+ }
+
+ #
+ # NOTE: The PGP signature was verified; use the downloaded package
+ # script verbatim.
+ #
+ set script(inner) $metadata(ifNeeded)
+
+ #
+ # NOTE: Determine the target language for the package script, which
+ # may or may not be the language that is currently evaluating
+ # this script (Eagle). The default language, when one was not
+ # explicitly specified, is Eagle. In the future, this may be
+ # changed, e.g. to use the file extension of the client script.
+ #
+ switch -exact -- $metadata(language) {
+ "" -
+ Eagle {
+ if {[isEagle]} then {
+ return [uplevel #0 $script(inner)]
+ } else {
+ eagleMustBeReady
+
+ return [eagle [list uplevel #0 $script(inner)]]
+ }
+ }
+ Tcl {
+ if {[isEagle]} then {
+ tclMustBeReady; return [tcl eval [tcl master] [list \
+ uplevel #0 $script(inner)]]
+ } else {
+ return [uplevel #0 $script(inner)]
+ }
+ }
+ default {
+ error "unsupported language"
+ }
+ }
+ }
} else {
error "unsupported script certificate"
}
}
Index: client/pkgr.eagle.harpy
==================================================================
--- client/pkgr.eagle.harpy
+++ client/pkgr.eagle.harpy
@@ -19,32 +19,32 @@
None
Mistachkin Systems
- ed124b1a-4d17-4891-8565-cca6d319e05d
+ 24efe138-647e-406e-a4ff-1d8728db1a30
SHA512
Script
- 2016-08-16T21:34:49.8991719Z
+ 2016-08-16T23:06:52.1540547Z
-1.00:00:00
0x2c322765603b5278
- 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
+ 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