diff --git a/cmd/a_main-packr.go b/cmd/a_main-packr.go index 20330af8..b0da00f3 100644 --- a/cmd/a_main-packr.go +++ b/cmd/a_main-packr.go @@ -7,5 +7,5 @@ import "github.com/gobuffalo/packr" // You can use the "packr clean" command to clean up this, // and any other packr generated files. func init() { - packr.PackJSONBytes("static", "default-config.toml", "\"IyMgQVRURU5USU9OCiMgaXQgaXMgZXhhbXBsZSBmaWxlIG9ubHkuIEl0IGJ1aWx0aW4gaW4gYmluYXJ5IGFuZCBkb24ndCByZWFkIGZyb20gZmlsZSBzeXN0ZW0uCiMgY2hhbmdlcyBpbiBjb25maWdfZGVmYXVsdC50b21sIGhhdmUgbm8gcmVhbCBlZmZlY3QuCgpbR2VuZXJhbF0KCiMgU2Vjb25kcyBmb3IgaXNzdWUgZXZlcnkgY2VydGlmaWNhdGUuIENhbmNlbCBpc3N1ZSBhbmQgcmV0dXJuIGVycm9yIGlmIHRpbWVvdXQuCklzc3VlVGltZW91dCA9IDMwMAoKIyBQYXRoIHRvIGRpciwgd2hpY2ggd2lsbCBzdG9yZSBzdGF0ZSBhbmQgY2VydGlmaWNhdGVzClN0b3JhZ2VEaXIgPSAic3RvcmFnZSIKCiMgU3RvcmUgLmpzb24gaW5mbyB3aXRoIGNlcnRpZmljYXRlIG1ldGFkYXRhIG5lYXIgY2VydGlmaWNhdGUuClN0b3JlSlNPTk1ldGFkYXRhID0gdHJ1ZQoKIyBEaXJlY3RvcnkgdXJsIG9mIGFjbWUgc2VydmVyLgojVGVzdCBzZXJ2ZXI6IGh0dHBzOi8vYWNtZS1zdGFnaW5nLmFwaS5sZXRzZW5jcnlwdC5vcmcvZGlyZWN0b3J5CkFjbWVTZXJ2ZXIgPSAiaHR0cHM6Ly9hY21lLXYwMS5hcGkubGV0c2VuY3J5cHQub3JnL2RpcmVjdG9yeSIKCiMgSW5jbHVkZSBvdGhlciBjb25maWcgZmlsZXMKIyBJdCBzdXBwb3J0IGdsb2Igc3ludGF4CiMgSWYgaXQgaGFzIHBhdGggd2l0aG91dCB0ZW1wbGF0ZSAtIHRoZSBmaWxlIG11c3QgZXhpc3QuCiMgRm9yIGFsbG93IG9wdGlvbmFsIGluY2x1ZGUgZmlsZSAtIGl0IGNhbiBjb250YWluIHNvbWUgZ2xvYiBzeW1ib2wKIyBJbmNsdWRlZCBjb25maWdzIG1lcmdlIHdpdGggY3VycmVudCByZWFkZWQgc3RhdGUuCiMgZXhhbXBsZT1bICJjb25maWcudG9tW2xdIiBdCkluY2x1ZGVDb25maWdzID0gW10KCiMgRm9yIHByZXZlbnQgaW5maW5pdGUgbG9vcCBhbmQgY29uc3VtZSBhbGwgbWVtb3J5IGlmIGN5Y2xlIGluIGluY2x1ZGVzCk1heENvbmZpZ0ZpbGVzUmVhZCA9IDEwMDAwCgpbTG9nXQpFbmFibGVMb2dUb0ZpbGUgPSB0cnVlCkVuYWJsZUxvZ1RvU3RkRXJyID0gdHJ1ZQoKIyB2ZXJib3NlIGxldmVsIG9mIGxvZywgb25lIG9mOiBkZWJ1ZywgaW5mbywgd2FybmluZywgZXJyb3IsIGZhdGFsCkxvZ0xldmVsID0gImluZm8iCgojIEVuYWJsZSBzZWxmIGxvZyByb3RhdGluZwpFbmFibGVSb3RhdGUgPSB0cnVlCgojIEVuYWJsZSBkZXZlbG9wZXIgbW9kZTogbW9yZSBzdGFja3RyYWNlcyBhbmQgcGFuaWMgKHN0b3AgcHJvZ3JhbSkgb24gc29tZSBpbnRlcm5hbCBlcnJvcnMuCkRldmVsb3Blck1vZGUgPSBmYWxzZQoKIyBQYXRoIHRvIGxvZyBmaWxlCkZpbGUgPSAibGV0cy1wcm94eS5sb2ciCgojIFJvdGF0ZSBsb2cgaWYgY3VycmVudCBmaWxlIHNpemUgbW9yZSB0aGFuIFggTUIKUm90YXRlQnlTaXplTUIgPSAxMDAKCiMgQ29tcHJlc3Mgb2xkIGxvZyB3aXRoIGd6aXAgYWZ0ZXIgcm90YXRlCkNvbXByZXNzUm90YXRlZCA9IGZhbHNlCgojIERlbGV0ZSBvbGQgYmFja3VwcyBhZnRlciBYIGRheXMuIDAgZm9yIGRpc2FibGUuCk1heERheXMgPSAxMAoKIyBEZWxldGUgb2xkIGJhY2t1cHMgaWYgb2xkIGZpbGUgbnVtYmVyIG1vcmUgdGhlbiBYLiAwIGZvciBkaXNhYmxlLgpNYXhDb3VudCA9IDEwCgpbUHJveHldCgojIERlZmF1bHQgcnVsZSBvZiBzZWxlY3QgZGVzdGluYXRpb24gYWRkcmVzcy4KI0l0IGNhbiBiZTogSVAgKHdpdGggZGVmYXVsdCBwb3J0IDgwKSwgOlBvcnQgKGRlZmF1bHQgLSBzYW1lIElQIGFzIHJlY2VpdmUgY29ubmVjdGlvbiksIElQdjQ6UG9ydCBvciBbSVB2Nl06UG9ydApEZWZhdWx0VGFyZ2V0ID0gIjo4MCIKCiMgQXJyYXkgb2YgJy0nIHNlcGFyYXRlZCBwYWlycyBvciBJUDpQb3J0LiBGb3IgZXhhbXBsZToKIyBbCiMgICAiMS4yLjMuNDo0NDMtMi4yLjIuMjoxMjM0IiwKIyAgICIzLjMuMy4zOjMzMy1bOjoxXTo5NCIKIyAiXQojIE1lYW46IGNvbm5lY3Rpb25zLCBhY2NlcHRlZCBvbiAxLjIuMy40OjQ0MyBzZW5kIHRvIHNlcnZlciAyLjIuMi4yOjEyMzQKIyBhbmQgY29ubmVjdGlvbnMgYWNjZXB0ZWQgb24gMy4zLjMuMzozMzMgc2VuZCB0byBpcHY2IDo6MSBwb3J0IDk0ClRhcmdldE1hcCA9IFtdCgojIEFycmF5IG9mIGNvbG9uIHNlcGFyYXRlZCBIZWFkZXJOYW1lOkhlYWRlclZhbHVlIGZvciBhZGQgdG8gcmVxdWVzdCBmb3IgYmFja2VuZC4ge3tWYWx1ZX19IGlzIHNwZWNpYWwgZm9ybXMsIHdoaWNoIGNhbgojIGludGVybmFsbHkgcGFyc2luZy4gTm93IGl0IHN1cHBvcnQgb25seSBzcGVjaWFsIHZhbHVlczoKIyB7e0NPTk5FQ1RJT05fSUR9fSAtIElkIG9mIGFjY2VwdGVkIGNvbm5lY3Rpb24sIGdlbmVyYXRlZCBieSBsZXRzLXByb3h5CiMge3tIVFRQX1BST1RPfX0gLSBzZXQgdG8gaHR0cC9odHRwcyBkZXBlbmRlbmNlIGluY29taW5nIGNvbm5lY3Rpb25zIGhhbmRsZWQKIyB7e1NPVVJDRV9JUH19IC0gUmVtb3RlIElQIG9mIGluY29taW5nIGNvbm5lY3Rpb24KIyB7U09VUkNFX1BPUlR9fSAtIFJlbW90ZSBwb3J0IG9mIGluY29taW5nIGNvbm5lY3Rpb24KIyB7e1NPVVJDRV9JUH19Ont7U09VUkNFX1BPUlR9fSAtIFJlbW90ZSBJUDpQb3J0IG9mIGluY29taW5nIGNvbm5lY3Rpb24uCiMgTm93IGl0IGFjY2VwdGVkIG9ubHkgdGhpcyBzcGVjaWFsIHZhbHVlcywgd2hpY2ggbXVzdCBiZSBleGF4bHR5IGVxdWFsIHRvIGV4YW1wbGVzLiBBbGwgb3RoZXIgdmFsdWVzIHNlbmQgYXMgaXMuCiMgQnV0IGl0IGNhbiBjaGFuZ2UgYW5kIGV4dGVuZCBpbiBmdXR1cmUuIERvZXNuJ3QgdXNlIHt7Li4ufX0gYXMgb3duIHZhbHVlcy4KIyBFeGFtcGxlOgojIFsiSVA6e3tTT1VSQ0VfSVB9fSIsICJQcm94eTpsZXRzLXByb3h5IiwgIlByb3RvY29sOnt7SFRUUF9QUk9UT319IiBdCkhlYWRlcnMgPSBbXQoKW0NoZWNrRG9tYWluc10KCiMgQWxsb3cgZG9tYWluIGlmIGl0IHJlc29sdmVyIGZvciBvbmUgb2YgcHVibGljIElQcyBvZiB0aGlzIHNlcnZlci4KSVBTZWxmID0gdHJ1ZQoKIyBBbGxvdyBkb21haW4gaWYgaXQgcmVzb2x2ZXIgZm9yIG9uZSBvZiB0aGUgaXBzLgpJUFdoaXRlTGlzdCA9ICIiCgojIFJlZ2V4cCBpbiBnb2xhbmcgc3ludGF4IG9mIGJsYWNrbGlzdGVkIGRvbWFpbiBmb3IgaXNzdWUgY2VydGlmaWNhdGUuCiNUaGlzIGxpc3Qgb3ZlcnJpZGVkIGJ5IHdoaXRlbGlzdC4KQmxhY2tMaXN0ID0gIiIKCiMgUmVnZXhwIGluIGdvbGFuZyBzeW50YXggb2Ygd2hpdGVsaXN0IGRvbWFpbnMgZm9yIGlzc3VlIGNlcnRpZmljYXRlLgojV2hpdGVsaXN0IG5lZWQgZm9yIGFsbG93IHBhcnQgb2YgZG9tYWlucywgd2hpY2ggZXhjbHVkZWQgYnkgYmxhY2tsaXN0LgojCldoaXRlTGlzdCA9ICIiCgojIENvbW1hIHNlcGFyYXRlZCBkbnMgc2VydmVyLCB1c2VkIGZvciByZXNvbHZlIGlwOnBvcnQgYWRkcmVzcyBvZiBkb21haW5zIHdoaWxlIGNoZWNrIGl0LgojIGlmIGVtcHR5IC0gdXNlIHN5c3RlbSBkbnMgcmVzb2x2ZXIgKHVzdWFsbHkgaW5jbHVkZSBob3N0cyBmaWxlLCBjYWNoZSwgZXRjKQojIGlmIHNldCAtIHVzZSBkaXJlY3QgZG5zIHF1ZXJpZXMgZm9yIHNlcnZlcnMsIHdpdGhvdXQgc2VsZiBjYWNoZS4KIyBpZiBzZXQgbW9yZSwgdGhhbiBvbmUgZG5zIHNlcnZlciAtIHNlbmQgcXVlcmllcyBpbiBwYXJhbGxlbCB0byBhbGwgc2VydmVycy4KIyBlcnJvciByZXN1bHRzIGZyb20gcGFydCBvZiBzZXJ2ZXJzIC0gaWdub3JlLiBOZWVkIG1pbmltdW0gb25lIGFuc3dlci4KIyBpZiBkaWZmZXJlbnQgZG5zIHNlcnZlcnMgcmV0dXJuIGRpZmZlcmVudCBpcCBhZGRyZXNzZXMgLSBhbGwgb2YgdGhlbSB1c2UgZm9yIGNoZWNrCiMgRXhhbXBsZTogIjguOC44Ljg6NTMsMS4xLjEuMTo1Myw3Ny44OC44Ljg6NTMsWzJhMDI6NmI4OjpmZWVkOjBmZl06NTMsWzIwMDE6NDg2MDo0ODYwOjo4ODg4XTo1MyIKUmVzb2x2ZXIgPSAiIgoKCgpbTGlzdGVuXQoKIyBCaW5kIGFkZHJlc3NlcyBmb3IgVExTIGxpc3RlbmVycwpUTFNBZGRyZXNzZXMgPSBbIjo0NDMiXQoKIyBCaW5kIGFkZHJlc3NlcyB3aXRob3V0IFRMUyBzZWN1cmUgKGZvciBIVFRQIHJldmVyc2UgcHJveHkgYW5kIGh0dHAtMDEgdmFsaWRhdGlvbiB3aXRob3V0IHJlZGlyZWN0IHRvIGh0dHBzKQpUQ1BBZGRyZXNzZXMgPSBbXQo=\"") + packr.PackJSONBytes("static", "default-config.toml", "\"IyMgQVRURU5USU9OCiMgaXQgaXMgZXhhbXBsZSBmaWxlIG9ubHkuIEl0IGJ1aWx0aW4gaW4gYmluYXJ5IGFuZCBkb24ndCByZWFkIGZyb20gZmlsZSBzeXN0ZW0uCiMgY2hhbmdlcyBpbiBjb25maWdfZGVmYXVsdC50b21sIGhhdmUgbm8gcmVhbCBlZmZlY3QuCgpbR2VuZXJhbF0KCiMgU2Vjb25kcyBmb3IgaXNzdWUgZXZlcnkgY2VydGlmaWNhdGUuIENhbmNlbCBpc3N1ZSBhbmQgcmV0dXJuIGVycm9yIGlmIHRpbWVvdXQuCklzc3VlVGltZW91dCA9IDMwMAoKIyBQYXRoIHRvIGRpciwgd2hpY2ggd2lsbCBzdG9yZSBzdGF0ZSBhbmQgY2VydGlmaWNhdGVzClN0b3JhZ2VEaXIgPSAic3RvcmFnZSIKCiMgU3RvcmUgLmpzb24gaW5mbyB3aXRoIGNlcnRpZmljYXRlIG1ldGFkYXRhIG5lYXIgY2VydGlmaWNhdGUuClN0b3JlSlNPTk1ldGFkYXRhID0gdHJ1ZQoKIyBEaXJlY3RvcnkgdXJsIG9mIGFjbWUgc2VydmVyLgojVGVzdCBzZXJ2ZXI6IGh0dHBzOi8vYWNtZS1zdGFnaW5nLmFwaS5sZXRzZW5jcnlwdC5vcmcvZGlyZWN0b3J5CkFjbWVTZXJ2ZXIgPSAiaHR0cHM6Ly9hY21lLXYwMS5hcGkubGV0c2VuY3J5cHQub3JnL2RpcmVjdG9yeSIKCiMgSW5jbHVkZSBvdGhlciBjb25maWcgZmlsZXMKIyBJdCBzdXBwb3J0IGdsb2Igc3ludGF4CiMgSWYgaXQgaGFzIHBhdGggd2l0aG91dCB0ZW1wbGF0ZSAtIHRoZSBmaWxlIG11c3QgZXhpc3QuCiMgRm9yIGFsbG93IG9wdGlvbmFsIGluY2x1ZGUgZmlsZSAtIGl0IGNhbiBjb250YWluIHNvbWUgZ2xvYiBzeW1ib2wKIyBJbmNsdWRlZCBjb25maWdzIG1lcmdlIHdpdGggY3VycmVudCByZWFkZWQgc3RhdGUuCiMgZXhhbXBsZT1bICJjb25maWcudG9tW2xdIiBdCkluY2x1ZGVDb25maWdzID0gW10KCiMgRm9yIHByZXZlbnQgaW5maW5pdGUgbG9vcCBhbmQgY29uc3VtZSBhbGwgbWVtb3J5IGlmIGN5Y2xlIGluIGluY2x1ZGVzCk1heENvbmZpZ0ZpbGVzUmVhZCA9IDEwMDAwCgpbTG9nXQpFbmFibGVMb2dUb0ZpbGUgPSB0cnVlCkVuYWJsZUxvZ1RvU3RkRXJyID0gdHJ1ZQoKIyB2ZXJib3NlIGxldmVsIG9mIGxvZywgb25lIG9mOiBkZWJ1ZywgaW5mbywgd2FybmluZywgZXJyb3IsIGZhdGFsCkxvZ0xldmVsID0gImluZm8iCgojIEVuYWJsZSBzZWxmIGxvZyByb3RhdGluZwpFbmFibGVSb3RhdGUgPSB0cnVlCgojIEVuYWJsZSBkZXZlbG9wZXIgbW9kZTogbW9yZSBzdGFja3RyYWNlcyBhbmQgcGFuaWMgKHN0b3AgcHJvZ3JhbSkgb24gc29tZSBpbnRlcm5hbCBlcnJvcnMuCkRldmVsb3Blck1vZGUgPSBmYWxzZQoKIyBQYXRoIHRvIGxvZyBmaWxlCkZpbGUgPSAibGV0cy1wcm94eS5sb2ciCgojIFJvdGF0ZSBsb2cgaWYgY3VycmVudCBmaWxlIHNpemUgbW9yZSB0aGFuIFggTUIKUm90YXRlQnlTaXplTUIgPSAxMDAKCiMgQ29tcHJlc3Mgb2xkIGxvZyB3aXRoIGd6aXAgYWZ0ZXIgcm90YXRlCkNvbXByZXNzUm90YXRlZCA9IGZhbHNlCgojIERlbGV0ZSBvbGQgYmFja3VwcyBhZnRlciBYIGRheXMuIDAgZm9yIGRpc2FibGUuCk1heERheXMgPSAxMAoKIyBEZWxldGUgb2xkIGJhY2t1cHMgaWYgb2xkIGZpbGUgbnVtYmVyIG1vcmUgdGhlbiBYLiAwIGZvciBkaXNhYmxlLgpNYXhDb3VudCA9IDEwCgpbUHJveHldCgojIERlZmF1bHQgcnVsZSBvZiBzZWxlY3QgZGVzdGluYXRpb24gYWRkcmVzcy4KI0l0IGNhbiBiZTogSVAgKHdpdGggZGVmYXVsdCBwb3J0IDgwKSwgOlBvcnQgKGRlZmF1bHQgLSBzYW1lIElQIGFzIHJlY2VpdmUgY29ubmVjdGlvbiksIElQdjQ6UG9ydCBvciBbSVB2Nl06UG9ydApEZWZhdWx0VGFyZ2V0ID0gIjo4MCIKCiMgQWZ0ZXIgS2VlcEFsaXZlVGltZW91dFNlY29uZHMgb2YgaW5hY3RpdmUgaW5jb21pbmcgY29ubmVjdGlvbiB3aWxsIGNsb3NlLgpLZWVwQWxpdmVUaW1lb3V0U2Vjb25kcyA9IDkwMAoKIyBBcnJheSBvZiAnLScgc2VwYXJhdGVkIHBhaXJzIG9yIElQOlBvcnQuIEZvciBleGFtcGxlOgojIFsKIyAgICIxLjIuMy40OjQ0My0yLjIuMi4yOjEyMzQiLAojICAgIjMuMy4zLjM6MzMzLVs6OjFdOjk0IgojICJdCiMgTWVhbjogY29ubmVjdGlvbnMsIGFjY2VwdGVkIG9uIDEuMi4zLjQ6NDQzIHNlbmQgdG8gc2VydmVyIDIuMi4yLjI6MTIzNAojIGFuZCBjb25uZWN0aW9ucyBhY2NlcHRlZCBvbiAzLjMuMy4zOjMzMyBzZW5kIHRvIGlwdjYgOjoxIHBvcnQgOTQKVGFyZ2V0TWFwID0gW10KCiMgQXJyYXkgb2YgY29sb24gc2VwYXJhdGVkIEhlYWRlck5hbWU6SGVhZGVyVmFsdWUgZm9yIGFkZCB0byByZXF1ZXN0IGZvciBiYWNrZW5kLiB7e1ZhbHVlfX0gaXMgc3BlY2lhbCBmb3Jtcywgd2hpY2ggY2FuCiMgaW50ZXJuYWxseSBwYXJzaW5nLiBOb3cgaXQgc3VwcG9ydCBvbmx5IHNwZWNpYWwgdmFsdWVzOgojIHt7Q09OTkVDVElPTl9JRH19IC0gSWQgb2YgYWNjZXB0ZWQgY29ubmVjdGlvbiwgZ2VuZXJhdGVkIGJ5IGxldHMtcHJveHkKIyB7e0hUVFBfUFJPVE99fSAtIHNldCB0byBodHRwL2h0dHBzIGRlcGVuZGVuY2UgaW5jb21pbmcgY29ubmVjdGlvbnMgaGFuZGxlZAojIHt7U09VUkNFX0lQfX0gLSBSZW1vdGUgSVAgb2YgaW5jb21pbmcgY29ubmVjdGlvbgojIHtTT1VSQ0VfUE9SVH19IC0gUmVtb3RlIHBvcnQgb2YgaW5jb21pbmcgY29ubmVjdGlvbgojIHt7U09VUkNFX0lQfX06e3tTT1VSQ0VfUE9SVH19IC0gUmVtb3RlIElQOlBvcnQgb2YgaW5jb21pbmcgY29ubmVjdGlvbi4KIyBOb3cgaXQgYWNjZXB0ZWQgb25seSB0aGlzIHNwZWNpYWwgdmFsdWVzLCB3aGljaCBtdXN0IGJlIGV4YXhsdHkgZXF1YWwgdG8gZXhhbXBsZXMuIEFsbCBvdGhlciB2YWx1ZXMgc2VuZCBhcyBpcy4KIyBCdXQgaXQgY2FuIGNoYW5nZSBhbmQgZXh0ZW5kIGluIGZ1dHVyZS4gRG9lc24ndCB1c2Uge3suLi59fSBhcyBvd24gdmFsdWVzLgojIEV4YW1wbGU6CiMgWyJJUDp7e1NPVVJDRV9JUH19IiwgIlByb3h5OmxldHMtcHJveHkiLCAiUHJvdG9jb2w6e3tIVFRQX1BST1RPfX0iIF0KSGVhZGVycyA9IFtdCgpbQ2hlY2tEb21haW5zXQoKIyBBbGxvdyBkb21haW4gaWYgaXQgcmVzb2x2ZXIgZm9yIG9uZSBvZiBwdWJsaWMgSVBzIG9mIHRoaXMgc2VydmVyLgpJUFNlbGYgPSB0cnVlCgojIEFsbG93IGRvbWFpbiBpZiBpdCByZXNvbHZlciBmb3Igb25lIG9mIHRoZSBpcHMuCklQV2hpdGVMaXN0ID0gIiIKCiMgUmVnZXhwIGluIGdvbGFuZyBzeW50YXggb2YgYmxhY2tsaXN0ZWQgZG9tYWluIGZvciBpc3N1ZSBjZXJ0aWZpY2F0ZS4KI1RoaXMgbGlzdCBvdmVycmlkZWQgYnkgd2hpdGVsaXN0LgpCbGFja0xpc3QgPSAiIgoKIyBSZWdleHAgaW4gZ29sYW5nIHN5bnRheCBvZiB3aGl0ZWxpc3QgZG9tYWlucyBmb3IgaXNzdWUgY2VydGlmaWNhdGUuCiNXaGl0ZWxpc3QgbmVlZCBmb3IgYWxsb3cgcGFydCBvZiBkb21haW5zLCB3aGljaCBleGNsdWRlZCBieSBibGFja2xpc3QuCiMKV2hpdGVMaXN0ID0gIiIKCiMgQ29tbWEgc2VwYXJhdGVkIGRucyBzZXJ2ZXIsIHVzZWQgZm9yIHJlc29sdmUgaXA6cG9ydCBhZGRyZXNzIG9mIGRvbWFpbnMgd2hpbGUgY2hlY2sgaXQuCiMgaWYgZW1wdHkgLSB1c2Ugc3lzdGVtIGRucyByZXNvbHZlciAodXN1YWxseSBpbmNsdWRlIGhvc3RzIGZpbGUsIGNhY2hlLCBldGMpCiMgaWYgc2V0IC0gdXNlIGRpcmVjdCBkbnMgcXVlcmllcyBmb3Igc2VydmVycywgd2l0aG91dCBzZWxmIGNhY2hlLgojIGlmIHNldCBtb3JlLCB0aGFuIG9uZSBkbnMgc2VydmVyIC0gc2VuZCBxdWVyaWVzIGluIHBhcmFsbGVsIHRvIGFsbCBzZXJ2ZXJzLgojIGVycm9yIHJlc3VsdHMgZnJvbSBwYXJ0IG9mIHNlcnZlcnMgLSBpZ25vcmUuIE5lZWQgbWluaW11bSBvbmUgYW5zd2VyLgojIGlmIGRpZmZlcmVudCBkbnMgc2VydmVycyByZXR1cm4gZGlmZmVyZW50IGlwIGFkZHJlc3NlcyAtIGFsbCBvZiB0aGVtIHVzZSBmb3IgY2hlY2sKIyBFeGFtcGxlOiAiOC44LjguODo1MywxLjEuMS4xOjUzLDc3Ljg4LjguODo1MyxbMmEwMjo2Yjg6OmZlZWQ6MGZmXTo1MyxbMjAwMTo0ODYwOjQ4NjA6Ojg4ODhdOjUzIgpSZXNvbHZlciA9ICIiCgoKCltMaXN0ZW5dCgojIEJpbmQgYWRkcmVzc2VzIGZvciBUTFMgbGlzdGVuZXJzClRMU0FkZHJlc3NlcyA9IFsiOjQ0MyJdCgojIEJpbmQgYWRkcmVzc2VzIHdpdGhvdXQgVExTIHNlY3VyZSAoZm9yIEhUVFAgcmV2ZXJzZSBwcm94eSBhbmQgaHR0cC0wMSB2YWxpZGF0aW9uIHdpdGhvdXQgcmVkaXJlY3QgdG8gaHR0cHMpClRDUEFkZHJlc3NlcyA9IFtdCg==\"") } diff --git a/cmd/static/default-config.toml b/cmd/static/default-config.toml index 6f820163..21a4ba36 100644 --- a/cmd/static/default-config.toml +++ b/cmd/static/default-config.toml @@ -62,6 +62,9 @@ MaxCount = 10 #It can be: IP (with default port 80), :Port (default - same IP as receive connection), IPv4:Port or [IPv6]:Port DefaultTarget = ":80" +# After KeepAliveTimeoutSeconds of inactive incoming connection will close. +KeepAliveTimeoutSeconds = 900 + # Array of '-' separated pairs or IP:Port. For example: # [ # "1.2.3.4:443-2.2.2.2:1234", diff --git a/internal/acme_client_manager/client_manager.go b/internal/acme_client_manager/client_manager.go index 25e64550..2cb1df5a 100644 --- a/internal/acme_client_manager/client_manager.go +++ b/internal/acme_client_manager/client_manager.go @@ -29,14 +29,14 @@ type AcmeManager struct { RenewAccountInterval time.Duration ctx context.Context - cache cache.Cache + cache cache.Bytes mu sync.Mutex client *acme.Client account *acme.Account } -func New(ctx context.Context, cache cache.Cache) *AcmeManager { +func New(ctx context.Context, cache cache.Bytes) *AcmeManager { return &AcmeManager{ ctx: ctx, cache: cache, diff --git a/internal/cache/interface.go b/internal/cache/interface.go index 61567094..f75ff0f3 100644 --- a/internal/cache/interface.go +++ b/internal/cache/interface.go @@ -7,7 +7,7 @@ import ( var ErrCacheMiss = errors.New("lets proxy: cache miss") -type Cache interface { +type Bytes interface { // Get returns a certificate data for the specified key. // If there's no such key, Get returns ErrCacheMiss. Get(ctx context.Context, key string) ([]byte, error) diff --git a/internal/cert_manager/manager.go b/internal/cert_manager/manager.go index 36ca3b9c..ba66b548 100644 --- a/internal/cert_manager/manager.go +++ b/internal/cert_manager/manager.go @@ -21,6 +21,7 @@ import ( "time" "github.com/rekby/lets-proxy2/internal/cache" + "go.uber.org/zap/zapcore" "github.com/rekby/lets-proxy2/internal/log" @@ -37,7 +38,7 @@ const ( const domainKeyRSALength = 2048 -var errHaveNoCert = errors.New("have no certificate for domain") +var errHaveNoCert = errors.New("have no certificate for domain") // may return for any internal error //nolint:varcheck,deadcode,unused var errNotImplementedError = errors.New("not implemented yet") @@ -55,7 +56,7 @@ const keyUnknown keyType = "unknown" // Interface inspired to https://godoc.org/golang.org/x/crypto/acme/autocert#Manager but not compatible guarantee type Manager struct { CertificateIssueTimeout time.Duration - Cache cache.Cache + Cache cache.Bytes // Client is used to perform low-level operations, such as account registration // and requesting new certificates. @@ -76,10 +77,10 @@ type Manager struct { certStateMu sync.Mutex certState cache.Value - httpTokens cache.Cache + httpTokens cache.Bytes } -func New(client AcmeClient, c cache.Cache) *Manager { +func New(client AcmeClient, c cache.Bytes) *Manager { res := Manager{} res.Client = client res.certForDomainAuthorize = cache.NewMemoryValueLRU("authcert") @@ -158,10 +159,14 @@ func (m *Manager) GetCertificate(hello *tls.ClientHelloInfo) (resultCert *tls.Ce locked, err := isCertLocked(ctx, m.Cache, certName) log.DebugDPanic(logger, err, "Check if certificate locked") - cert, err = getCertificate(ctx, m.Cache, certName, keyRSA) - if err == nil { - logger.Debug("Certificate loaded from cache") + cert, err = loadCertificateFromCache(ctx, m.Cache, certName, keyRSA) + logLevel := zapcore.DebugLevel + if err != nil && err != cache.ErrCacheMiss { + logLevel = zapcore.ErrorLevel + } + log.LevelParam(logger, logLevel, "Load certificate from cache", zap.Error(err)) + if err == nil { cert, err = validCertDer([]DomainName{needDomain}, cert.Certificate, cert.PrivateKey, locked, now) logger.Debug("Check if certificate ok", zap.Error(err)) if err == nil { @@ -169,6 +174,9 @@ func (m *Manager) GetCertificate(hello *tls.ClientHelloInfo) (resultCert *tls.Ce return cert, nil } } + if err != cache.ErrCacheMiss { + return nil, errHaveNoCert + } if locked { return nil, errHaveNoCert @@ -598,7 +606,7 @@ func (m *Manager) deleteCertToken(ctx context.Context, key DomainName) { } // It isn't atomic syncronized - caller must not save two certificates with same name same time -func storeCertificate(ctx context.Context, cache cache.Cache, certName certNameType, +func storeCertificate(ctx context.Context, cache cache.Bytes, certName certNameType, cert *tls.Certificate) error { logger := zc.L(ctx) if cache == nil { @@ -662,7 +670,7 @@ func storeCertificate(ctx context.Context, cache cache.Cache, certName certNameT return nil } -func storeCertificateMeta(ctx context.Context, storage cache.Cache, key certNameType, certificate *tls.Certificate) error { +func storeCertificateMeta(ctx context.Context, storage cache.Bytes, key certNameType, certificate *tls.Certificate) error { info := struct { Domains []string ExpireDate time.Time @@ -693,7 +701,7 @@ func getKeyType(cert *tls.Certificate) keyType { } } -func getCertificate(ctx context.Context, cache cache.Cache, certName certNameType, keyType keyType) (cert *tls.Certificate, err error) { +func loadCertificateFromCache(ctx context.Context, c cache.Bytes, certName certNameType, keyType keyType) (cert *tls.Certificate, err error) { logger := zc.L(ctx) logger.Debug("Check certificate in cache") defer func() { @@ -702,38 +710,45 @@ func getCertificate(ctx context.Context, cache cache.Cache, certName certNameTyp certKeyName := string(certName) + "." + string(keyType) + ".cer" - certBytes, err := cache.Get(ctx, certKeyName) + certBytes, err := c.Get(ctx, certKeyName) + log.DebugError(logger, err, "Get certificate from cache") if err != nil { return nil, err } - keyBytes, err := getCertificateKeyBytes(ctx, cache, certName, keyType) + keyBytes, err := getCertificateKeyBytes(ctx, c, certName, keyType) + log.DebugError(logger, err, "Get certificate key from cache") if err != nil { return nil, err } cert2, err := tls.X509KeyPair(certBytes, keyBytes) + log.DebugError(logger, err, "Combine cert and key into pair") if err != nil { + // logical error, may be system failure return nil, err } if len(cert2.Certificate) > 0 { cert2.Leaf, err = x509.ParseCertificate(cert2.Certificate[0]) if err != nil { + // logical error, may be system failure return nil, err } } - locked, err := isCertLocked(ctx, cache, certName) + locked, err := isCertLocked(ctx, c, certName) + log.DebugError(logger, err, "Check if certificate locked") if err != nil { + // logical error, may be system failure return nil, err } return validCertTLS(&cert2, nil, locked, time.Now()) } -func getCertificateKeyBytes(ctx context.Context, cache cache.Cache, certName certNameType, keyType keyType) ([]byte, error) { +func getCertificateKeyBytes(ctx context.Context, cache cache.Bytes, certName certNameType, keyType keyType) ([]byte, error) { keyKeyName := string(certName) + "." + string(keyType) + ".key" return cache.Get(ctx, keyKeyName) } -func getCertificateKey(ctx context.Context, cache cache.Cache, certName certNameType, keyType keyType) (crypto.Signer, error) { +func getCertificateKey(ctx context.Context, cache cache.Bytes, certName certNameType, keyType keyType) (crypto.Signer, error) { certBytes, err := getCertificateKeyBytes(ctx, cache, certName, keyType) if err != nil { return nil, err @@ -799,7 +814,7 @@ func isNeedRenew(cert *tls.Certificate, now time.Time) bool { return cert.Leaf.NotAfter.Add(-time.Hour * 24 * 30).Before(now) } -func isCertLocked(ctx context.Context, storage cache.Cache, certName certNameType) (bool, error) { +func isCertLocked(ctx context.Context, storage cache.Bytes, certName certNameType) (bool, error) { lockName := certName.String() + ".lock" _, err := storage.Get(ctx, lockName) switch err { diff --git a/internal/log/log.go b/internal/log/log.go index 9d4bea89..e5f8c06e 100644 --- a/internal/log/log.go +++ b/internal/log/log.go @@ -7,6 +7,7 @@ import ( "fmt" zc "github.com/rekby/zapcontext" + "go.uber.org/zap/zapcore" "go.uber.org/zap" ) @@ -169,3 +170,9 @@ func infoPanic(logger *zap.Logger, err error, mess string, fields ...zap.Field) logger.Panic(mess, append(fields, zap.Error(err))...) } } + +func LevelParam(logger *zap.Logger, level zapcore.Level, mess string, fields ...zap.Field) { + if ce := logger.Check(level, mess); ce != nil { + ce.Write(fields...) + } +} diff --git a/internal/proxy/config.go b/internal/proxy/config.go index e713032f..cc4219cd 100644 --- a/internal/proxy/config.go +++ b/internal/proxy/config.go @@ -6,6 +6,7 @@ import ( "fmt" "net" "strings" + "time" "github.com/rekby/lets-proxy2/internal/log" @@ -18,9 +19,10 @@ const defaultHTTPPort = 80 //nolint:lll type Config struct { - DefaultTarget string - TargetMap []string - Headers []string + DefaultTarget string + TargetMap []string + Headers []string + KeepAliveTimeoutSeconds int } func (c *Config) Apply(ctx context.Context, p *HTTPProxy) error { @@ -46,6 +48,7 @@ func (c *Config) Apply(ctx context.Context, p *HTTPProxy) error { chainDirector := NewDirectorChain(chain...) p.Director = chainDirector + p.IdleTimeout = time.Duration(c.KeepAliveTimeoutSeconds) * time.Second return nil } diff --git a/internal/proxy/http-proxy.go b/internal/proxy/http-proxy.go index 7c639cf9..eba296e7 100644 --- a/internal/proxy/http-proxy.go +++ b/internal/proxy/http-proxy.go @@ -6,6 +6,7 @@ import ( "net/http" "net/http/httputil" "net/url" + "time" "github.com/rekby/lets-proxy2/internal/contexthelper" @@ -31,6 +32,7 @@ type HTTPProxy struct { ctx context.Context listener net.Listener httpReverseProxy httputil.ReverseProxy + IdleTimeout time.Duration } func NewHTTPProxy(ctx context.Context, listener net.Listener) *HTTPProxy { @@ -64,6 +66,7 @@ func (p *HTTPProxy) Start() error { }) httpServer := http.Server{} httpServer.Handler = mux + httpServer.IdleTimeout = p.IdleTimeout go func() { <-p.ctx.Done()