Compare commits
10 Commits
fa23951802
...
132abcfd2d
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
132abcfd2d | ||
|
|
cafa0182eb | ||
|
|
4b488515eb | ||
|
|
c9cd171d6f | ||
|
|
0913336aed | ||
|
|
57db542958 | ||
|
|
376f1c2508 | ||
|
|
23c2fd6596 | ||
|
|
0e933663d9 | ||
|
|
77a4ad47f8 |
9
GENERATED_ipng.go
Normal file
9
GENERATED_ipng.go
Normal file
File diff suppressed because one or more lines are too long
@@ -46,11 +46,11 @@ func qrchFromRequest(r *http.Request) *qrbill.QRCH {
|
||||
IBAN: ifEmpty(r.Form, "criban", "CH0209000000870913543"),
|
||||
Cdtr: qrbill.Address{
|
||||
AdrTp: qrbill.AddressType(ifEmpty(r.Form, "craddrtype", string(qrbill.AddressTypeStructured))),
|
||||
Name: ifEmpty(r.Form, "crname", "Legalize it"),
|
||||
StrtNmOrAdrLine1: ifEmpty(r.Form, "craddr1", "Quellenstrasse"),
|
||||
BldgNbOrAdrLine2: ifEmpty(r.Form, "craddr2", "25"),
|
||||
PstCd: ifEmpty(r.Form, "crpost", "8005"),
|
||||
TwnNm: ifEmpty(r.Form, "crcity", "Zürich"),
|
||||
Name: ifEmpty(r.Form, "crname", "IPng Networks GmbH"),
|
||||
StrtNmOrAdrLine1: ifEmpty(r.Form, "craddr1", "Im Bungert"),
|
||||
BldgNbOrAdrLine2: ifEmpty(r.Form, "craddr2", "14"),
|
||||
PstCd: ifEmpty(r.Form, "crpost", "8306"),
|
||||
TwnNm: ifEmpty(r.Form, "crcity", "Brüttisellen"),
|
||||
Ctry: ifEmpty(r.Form, "crcountry", "CH"),
|
||||
},
|
||||
},
|
||||
@@ -59,19 +59,19 @@ func qrchFromRequest(r *http.Request) *qrbill.QRCH {
|
||||
Ccy: "CHF",
|
||||
},
|
||||
UltmtDbtr: qrbill.Address{
|
||||
AdrTp: qrbill.AddressType(ifEmpty(r.Form, "udaddrtype", string(qrbill.AddressTypeCombined))),
|
||||
Name: ifEmpty(r.Form, "udname", "Michael Stapelberg"),
|
||||
StrtNmOrAdrLine1: ifEmpty(r.Form, "udaddr1", "Stauffacherstr 42"),
|
||||
BldgNbOrAdrLine2: ifEmpty(r.Form, "udaddr2", "8004 Zürich"),
|
||||
PstCd: ifEmpty(r.Form, "udpost", ""),
|
||||
TwnNm: ifEmpty(r.Form, "udcity", ""),
|
||||
AdrTp: qrbill.AddressType(ifEmpty(r.Form, "udaddrtype", string(qrbill.AddressTypeStructured))),
|
||||
Name: ifEmpty(r.Form, "udname", "IPng Networks GmbH"),
|
||||
StrtNmOrAdrLine1: ifEmpty(r.Form, "udaddr1", "Im Bungert"),
|
||||
BldgNbOrAdrLine2: ifEmpty(r.Form, "udaddr2", "14"),
|
||||
PstCd: ifEmpty(r.Form, "udpost", "8306"),
|
||||
TwnNm: ifEmpty(r.Form, "udcity", "Brüttisellen"),
|
||||
Ctry: ifEmpty(r.Form, "udcountry", "CH"),
|
||||
},
|
||||
RmtInf: qrbill.QRCHRmtInf{
|
||||
Tp: "NON", // Reference type
|
||||
Ref: "", // Reference
|
||||
AddInf: qrbill.QRCHRmtInfAddInf{
|
||||
Ustrd: ifEmpty(r.Form, "message", "Spende 420"),
|
||||
Ustrd: ifEmpty(r.Form, "message", "IPng Networks GmbH invoice"),
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
17
go.mod
17
go.mod
@@ -1,13 +1,16 @@
|
||||
module github.com/stapelberg/qrbill
|
||||
|
||||
go 1.14
|
||||
go 1.25
|
||||
|
||||
require (
|
||||
github.com/ajstarks/svgo v0.0.0-20200725142600-7a3c8b57fecb
|
||||
github.com/ajstarks/svgo v0.0.0-20211024235047-1546f124cd8b
|
||||
github.com/davecgh/go-spew v1.1.1
|
||||
github.com/makiuchi-d/gozxing v0.0.0-20200903113411-25f730ed83da
|
||||
github.com/mattn/go-isatty v0.0.12
|
||||
golang.org/x/sys v0.0.0-20200724161237-0e2f3a69832c // indirect
|
||||
golang.org/x/text v0.3.4 // indirect
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect
|
||||
github.com/makiuchi-d/gozxing v0.1.1
|
||||
github.com/mattn/go-isatty v0.0.20
|
||||
)
|
||||
|
||||
require (
|
||||
golang.org/x/sys v0.16.0 // indirect
|
||||
golang.org/x/text v0.14.0 // indirect
|
||||
golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028 // indirect
|
||||
)
|
||||
|
||||
52
go.sum
52
go.sum
@@ -1,18 +1,42 @@
|
||||
github.com/ajstarks/svgo v0.0.0-20200725142600-7a3c8b57fecb h1:EVl3FJLQCzSbgBezKo/1A4ADnJ4mtJZ0RvnNzDJ44nY=
|
||||
github.com/ajstarks/svgo v0.0.0-20200725142600-7a3c8b57fecb/go.mod h1:K08gAheRH3/J6wwsYMMT4xOr94bZjxIelGM0+d/wbFw=
|
||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||
github.com/ajstarks/deck v0.0.0-20200831202436-30c9fc6549a9/go.mod h1:JynElWSGnm/4RlzPXRlREEwqTHAN3T56Bv2ITsFT3gY=
|
||||
github.com/ajstarks/deck/generate v0.0.0-20210309230005-c3f852c02e19/go.mod h1:T13YZdzov6OU0A1+RfKZiZN9ca6VeKdBdyDV+BY97Tk=
|
||||
github.com/ajstarks/svgo v0.0.0-20211024235047-1546f124cd8b h1:slYM766cy2nI3BwyRiyQj/Ud48djTMtMebDqepE95rw=
|
||||
github.com/ajstarks/svgo v0.0.0-20211024235047-1546f124cd8b/go.mod h1:1KcenG0jGWcpt8ov532z81sp/kMMUG485J2InIOyADM=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/makiuchi-d/gozxing v0.0.0-20200903113411-25f730ed83da h1:OgNu1PPD9EvZckyKDAc8DA4KymNXuc6vaCLsdOGyjOE=
|
||||
github.com/makiuchi-d/gozxing v0.0.0-20200903113411-25f730ed83da/go.mod h1:WoI7z45M7ZNA5BJxiJHaB+x7+k8S/3phW5Y13IR4yWY=
|
||||
github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY=
|
||||
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
|
||||
golang.org/x/sys v0.0.0-20200116001909-b77594299b42 h1:vEOn+mP2zCOVzKckCZy6YsCtDblrpj/w7B9nxGNELpg=
|
||||
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200724161237-0e2f3a69832c h1:UIcGWL6/wpCfyGuJnRFJRurA+yj8RrW7Q6x2YMCXt6c=
|
||||
golang.org/x/sys v0.0.0-20200724161237-0e2f3a69832c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/text v0.3.4 h1:0YWbFKbhXG/wIiuHDSKpS0Iy7FSA+u45VtBMfQcFTTc=
|
||||
golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e h1:FDhOuMEY4JVRztM/gsbk+IKUQ8kj74bxZrgw87eMMVc=
|
||||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||
github.com/makiuchi-d/gozxing v0.1.1 h1:xxqijhoedi+/lZlhINteGbywIrewVdVv2wl9r5O9S1I=
|
||||
github.com/makiuchi-d/gozxing v0.1.1/go.mod h1:eRIHbOjX7QWxLIDJoQuMLhuXg9LAuw6znsUtRkNw9DU=
|
||||
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
|
||||
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
||||
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.16.0 h1:xWw16ngr6ZMtmxDyKyIgsE93KNKz5HKmMa3b8ALHidU=
|
||||
golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
|
||||
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
|
||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028 h1:+cNy6SZtPcJQH3LJVLOSmiC7MMxXNOb3PU/VUEz+EhU=
|
||||
golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028/go.mod h1:NDW/Ps6MPRej6fsCIbMTohpP40sJ/P/vI1MoTEGwX90=
|
||||
honnef.co/go/tools v0.1.3/go.mod h1:NgwopIslSNH47DimFoV78dnkksY2EFtX0ajyb3K/las=
|
||||
|
||||
57
logo.svg
Normal file
57
logo.svg
Normal file
File diff suppressed because one or more lines are too long
|
After Width: | Height: | Size: 8.2 KiB |
44
qrbill.go
44
qrbill.go
@@ -18,8 +18,8 @@
|
||||
// was the Swiss Payment Standards 2019 Swiss Implementation Guidelines QR-bill
|
||||
// Version 2.1, to be found at:
|
||||
//
|
||||
// https://www.paymentstandards.ch/dam/downloads/ig-qr-bill-en.pdf (English)
|
||||
// https://www.paymentstandards.ch/dam/downloads/ig-qr-bill-de.pdf (German)
|
||||
// https://www.six-group.com/dam/download/banking-services/standardization/qr-bill/ig-qr-bill-v2.1-en.pdf (English)
|
||||
// https://www.six-group.com/dam/download/banking-services/standardization/qr-bill/ig-qr-bill-v2.1-de.pdf (German)
|
||||
//
|
||||
// # Note
|
||||
//
|
||||
@@ -28,8 +28,11 @@ package qrbill
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"image"
|
||||
"log"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/makiuchi-d/gozxing/qrcode/decoder"
|
||||
@@ -124,6 +127,37 @@ type QRCHCcyAmt struct {
|
||||
Ccy string // Currency
|
||||
}
|
||||
|
||||
func (a QRCHCcyAmt) Validate() QRCHCcyAmt {
|
||||
c := a
|
||||
|
||||
if c.Amt != "" {
|
||||
parsed, err := strconv.ParseFloat(c.Amt, 64)
|
||||
if err != nil {
|
||||
log.Printf("ParseFloat(%q): %v", c.Amt, err)
|
||||
}
|
||||
|
||||
// The Swiss Payment Standards 2019 Swiss Implementation Guidelines
|
||||
// QR-bill Version 2.3 explains:
|
||||
//
|
||||
// The amount element is to be entered without leading
|
||||
// zeroes, including decimal separators and two decimal
|
||||
// places.
|
||||
// Decimal, maximum 12-digits permitted, including decimal
|
||||
// separators. Only decimal points (".") are permitted as
|
||||
// decimal separators. The amount must be between CHF/
|
||||
// EUR 0.01 and 999,999,999.99
|
||||
//
|
||||
// (Notably, the validator is less strict and also permits values
|
||||
// without decimal separators or with only one decimal place.)
|
||||
//
|
||||
// Some banking apps are picky regarding integer numbers (e.g. 50) and
|
||||
// require a separator plus two digits (e.g. 50.00).
|
||||
c.Amt = fmt.Sprintf("%.2f", parsed)
|
||||
}
|
||||
|
||||
return c
|
||||
}
|
||||
|
||||
type QRCHRmtInfAddInf struct {
|
||||
Ustrd string // Unstructured message
|
||||
Trailer string // Trailer
|
||||
@@ -194,6 +228,8 @@ func (q *QRCH) Validate() *QRCH {
|
||||
|
||||
clone.UltmtDbtr = clone.UltmtDbtr.Validate()
|
||||
|
||||
clone.CcyAmt = clone.CcyAmt.Validate()
|
||||
|
||||
clone.RmtInf.Tp = nonAlphanumericRe.ReplaceAllString(clone.RmtInf.Tp, "")
|
||||
if v := clone.RmtInf.Tp; len(v) > 4 {
|
||||
clone.RmtInf.Tp = v[:4]
|
||||
@@ -282,8 +318,8 @@ func (b *Bill) EncodeToSVG() ([]byte, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// overlay the swiss cross
|
||||
cross := swisscross["swisscross.svg"]
|
||||
// overlay the IPng Logo
|
||||
cross := ipng["logo.svg"]
|
||||
// Remove XML document header, we embed the <svg> element:
|
||||
cross = bytes.ReplaceAll(cross, []byte(`<?xml version="1.0" encoding="utf-8"?>`), nil)
|
||||
// Overwrite position and size of the embedded <svg> element:
|
||||
|
||||
124
qrbill_test.go
Normal file
124
qrbill_test.go
Normal file
@@ -0,0 +1,124 @@
|
||||
package qrbill_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stapelberg/qrbill"
|
||||
)
|
||||
|
||||
func TestAmountValidation(t *testing.T) {
|
||||
for _, tt := range []struct {
|
||||
amount string
|
||||
wantAmount string
|
||||
}{
|
||||
{
|
||||
// ensure empty amount values are not modified
|
||||
amount: "",
|
||||
wantAmount: "",
|
||||
},
|
||||
|
||||
{
|
||||
amount: "50",
|
||||
wantAmount: "50.00",
|
||||
},
|
||||
|
||||
{
|
||||
amount: "50.3",
|
||||
wantAmount: "50.30",
|
||||
},
|
||||
|
||||
{
|
||||
amount: "50.32",
|
||||
wantAmount: "50.32",
|
||||
},
|
||||
|
||||
{
|
||||
amount: "50.32",
|
||||
wantAmount: "50.32",
|
||||
},
|
||||
|
||||
{
|
||||
amount: "50.000",
|
||||
wantAmount: "50.00",
|
||||
},
|
||||
|
||||
{
|
||||
amount: "50.339",
|
||||
wantAmount: "50.34",
|
||||
},
|
||||
|
||||
{
|
||||
amount: "50.331",
|
||||
wantAmount: "50.33",
|
||||
},
|
||||
|
||||
{
|
||||
amount: "50.-",
|
||||
wantAmount: "0.00", // result of invalid input
|
||||
},
|
||||
|
||||
{
|
||||
amount: ".30",
|
||||
wantAmount: "0.30",
|
||||
},
|
||||
|
||||
{
|
||||
amount: ".3",
|
||||
wantAmount: "0.30",
|
||||
},
|
||||
|
||||
{
|
||||
// minimum amount mentioned in the Implementation Guidelines
|
||||
amount: "0.01",
|
||||
wantAmount: "0.01",
|
||||
},
|
||||
|
||||
{
|
||||
// maximum amount mentioned in the Implementation Guidelines
|
||||
amount: "999999999.99",
|
||||
wantAmount: "999999999.99",
|
||||
},
|
||||
} {
|
||||
t.Run(tt.amount, func(t *testing.T) {
|
||||
qrch := &qrbill.QRCH{
|
||||
CdtrInf: qrbill.QRCHCdtrInf{
|
||||
IBAN: "CH0209000000870913543",
|
||||
Cdtr: qrbill.Address{
|
||||
AdrTp: qrbill.AddressTypeStructured,
|
||||
Name: "Legalize it",
|
||||
StrtNmOrAdrLine1: "Quellenstrasse",
|
||||
BldgNbOrAdrLine2: "25",
|
||||
PstCd: "8005",
|
||||
TwnNm: "Zürich",
|
||||
Ctry: "CH",
|
||||
},
|
||||
},
|
||||
CcyAmt: qrbill.QRCHCcyAmt{
|
||||
Amt: tt.amount,
|
||||
Ccy: "CHF",
|
||||
},
|
||||
UltmtDbtr: qrbill.Address{
|
||||
AdrTp: qrbill.AddressTypeStructured,
|
||||
Name: "Michael Stapelberg",
|
||||
StrtNmOrAdrLine1: "Stauffacherstr",
|
||||
BldgNbOrAdrLine2: "42",
|
||||
PstCd: "8004",
|
||||
TwnNm: "Zürich",
|
||||
Ctry: "CH",
|
||||
},
|
||||
RmtInf: qrbill.QRCHRmtInf{
|
||||
Tp: "NON", // Reference type
|
||||
Ref: "", // Reference
|
||||
AddInf: qrbill.QRCHRmtInfAddInf{
|
||||
Ustrd: "test",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
validated := qrch.Validate()
|
||||
if got, want := validated.CcyAmt.Amt, tt.wantAmount; got != want {
|
||||
t.Errorf("CcyAmt.Amt = %q, want %q", got, want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -20,7 +20,6 @@ import (
|
||||
"image/draw"
|
||||
|
||||
"github.com/makiuchi-d/gozxing"
|
||||
"github.com/makiuchi-d/gozxing/common"
|
||||
"github.com/makiuchi-d/gozxing/qrcode"
|
||||
"github.com/makiuchi-d/gozxing/qrcode/decoder"
|
||||
)
|
||||
@@ -61,7 +60,7 @@ func qrEncodeHints() map[gozxing.EncodeHintType]interface{} {
|
||||
|
||||
// Section 4.2.1: Character set:
|
||||
// UTF-8 should be used for encoding
|
||||
gozxing.EncodeHintType_CHARACTER_SET: common.CharacterSetECI_UTF8,
|
||||
gozxing.EncodeHintType_CHARACTER_SET: "UTF-8",
|
||||
}
|
||||
}
|
||||
|
||||
@@ -79,7 +78,7 @@ func generateQrCodeImage(payload string) (image.Image, error) {
|
||||
}
|
||||
|
||||
func overlayWithSwissCross(qrCodeImage image.Image) (image.Image, error) {
|
||||
b := swisscross["third_party/swiss-cross/CH-Kreuz_7mm/CH-Kreuz_7mm.png"]
|
||||
b := ipng["logo-inverted.png"]
|
||||
swissCrossImage, _, err := image.Decode(bytes.NewReader(b))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
||||
45
systemd/qrbill.service
Normal file
45
systemd/qrbill.service
Normal file
@@ -0,0 +1,45 @@
|
||||
[Unit]
|
||||
Description=qrbill
|
||||
|
||||
[Service]
|
||||
ExecStart=/usr/local/bin/qrbill-api
|
||||
|
||||
# See also http://0pointer.net/blog/dynamic-users-with-systemd.html
|
||||
DynamicUser=yes
|
||||
|
||||
# Remove all capabilities(7), this is a stateless web server:
|
||||
CapabilityBoundingSet=
|
||||
|
||||
# Ensure the service can never gain new privileges:
|
||||
NoNewPrivileges=yes
|
||||
|
||||
# Prohibit access to any kind of namespacing:
|
||||
RestrictNamespaces=yes
|
||||
|
||||
# Make home directories inaccessible:
|
||||
ProtectHome=true
|
||||
|
||||
# Make device nodes except for /dev/null, /dev/zero, /dev/full,
|
||||
# /dev/random and /dev/urandom inaccessible:
|
||||
PrivateDevices=yes
|
||||
|
||||
# Make users other than root and the user for this daemon inaccessible:
|
||||
PrivateUsers=yes
|
||||
|
||||
# Make cgroup file system hierarchy inaccessible:
|
||||
ProtectControlGroups=yes
|
||||
|
||||
# Deny kernel module loading:
|
||||
ProtectKernelModules=yes
|
||||
|
||||
# Make kernel variables (e.g. /proc/sys) read-only:
|
||||
ProtectKernelTunables=yes
|
||||
|
||||
# Filter dangerous system calls. The following is listed as safe basic choice
|
||||
# in systemd.exec(5):
|
||||
SystemCallArchitectures=native
|
||||
SystemCallFilter=@system-service
|
||||
SystemCallErrorNumber=EPERM
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
Reference in New Issue
Block a user