config download

This commit is contained in:
Christoph Haas 2023-07-04 22:55:11 +02:00
parent 9fdb8d8633
commit bbb00de25b
6 changed files with 136 additions and 19 deletions

View File

@ -66,6 +66,29 @@ watch(() => props.visible, async (newValue, oldValue) => {
}
)
function download() {
// credit: https://www.bitdegree.org/learn/javascript-download
let filename = 'WireGuard-Tunnel.conf'
if (selectedPeer.value.DisplayName) {
filename = selectedPeer.value.DisplayName
.replace(/ /g,"_")
.replace(/[^a-zA-Z0-9-_]/g,"")
.substring(0, 16)
+ ".conf"
}
let text = configString.value
let element = document.createElement('a')
element.setAttribute('href', 'data:text/plain;charset=utf-8,' + encodeURIComponent(text))
element.setAttribute('download', filename)
element.style.display = 'none'
document.body.appendChild(element)
element.click()
document.body.removeChild(element)
}
</script>
<template>
@ -116,7 +139,7 @@ watch(() => props.visible, async (newValue, oldValue) => {
</template>
<template #footer>
<div class="flex-fill text-start">
<button type="button" class="btn btn-primary me-1">Download</button>
<button @click.prevent="download" type="button" class="btn btn-primary me-1">Download</button>
<button type="button" class="btn btn-primary me-1">Email</button>
</div>
<button @click.prevent="close" type="button" class="btn btn-secondary">Close</button>

View File

@ -24,6 +24,24 @@ function calculateInterfaceName(id, name) {
return result
}
async function download() {
await interfaces.LoadInterfaceConfig(interfaces.GetSelected.Identifier)
// credit: https://www.bitdegree.org/learn/javascript-download
let filename = interfaces.GetSelected.Identifier + ".conf"
let text = interfaces.configuration
let element = document.createElement('a')
element.setAttribute('href', 'data:text/plain;charset=utf-8,' + encodeURIComponent(text))
element.setAttribute('download', filename)
element.style.display = 'none'
document.body.appendChild(element)
element.click()
document.body.removeChild(element)
}
onMounted(async () => {
await interfaces.LoadInterfaces()
await peers.LoadPeers()
@ -80,7 +98,7 @@ onMounted(async () => {
</div>
<div class="col-12 col-lg-4 text-lg-end">
<a class="btn-link" href="#" title="Show interface configuration" @click.prevent="viewedInterfaceId=interfaces.GetSelected.Identifier"><i class="fas fa-eye"></i></a>
<a class="ms-5 btn-link" href="#" title="Download interface configuration"><i class="fas fa-download"></i></a>
<a class="ms-5 btn-link" href="#" title="Download interface configuration" @click.prevent="download"><i class="fas fa-download"></i></a>
<a class="ms-5 btn-link" href="#" title="Write interface configuration file"><i class="fas fa-save"></i></a>
<a class="ms-5 btn-link" href="#" title="Edit interface settings" @click.prevent="editInterfaceId=interfaces.GetSelected.Identifier"><i class="fas fa-cog"></i></a>
</div>

5
go.mod
View File

@ -20,7 +20,6 @@ require (
github.com/vishvananda/netlink v1.1.0
github.com/xhit/go-simple-mail/v2 v2.13.0
github.com/yeqown/go-qrcode/v2 v2.2.1
github.com/yeqown/go-qrcode/writer/standard v1.2.1
golang.org/x/crypto v0.10.0
golang.org/x/oauth2 v0.9.0
golang.zx2c4.com/wireguard/wgctrl v0.0.0-20230429144221-925a1e7659e6
@ -39,7 +38,6 @@ require (
github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/dchest/uniuri v1.2.0 // indirect
github.com/fogleman/gg v1.3.0 // indirect
github.com/gabriel-vasile/mimetype v1.4.2 // indirect
github.com/gin-contrib/sse v0.1.0 // indirect
github.com/go-asn1-ber/asn1-ber v1.5.4 // indirect
@ -56,7 +54,6 @@ require (
github.com/goccy/go-json v0.10.2 // indirect
github.com/golang-sql/civil v0.0.0-20220223132316-b832511892a9 // indirect
github.com/golang-sql/sqlexp v0.1.0 // indirect
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 // indirect
github.com/golang/protobuf v1.5.3 // indirect
github.com/google/go-cmp v0.5.9 // indirect
github.com/google/uuid v1.3.0 // indirect
@ -83,7 +80,6 @@ require (
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/pelletier/go-toml/v2 v2.0.8 // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/quasoft/memstore v0.0.0-20191010062613-2bce066d2b0b // indirect
github.com/stretchr/objx v0.5.0 // indirect
@ -93,7 +89,6 @@ require (
github.com/vishvananda/netns v0.0.4 // indirect
github.com/yeqown/reedsolomon v1.0.0 // indirect
golang.org/x/arch v0.3.0 // indirect
golang.org/x/image v0.0.0-20200927104501-e162460cd6b5 // indirect
golang.org/x/net v0.11.0 // indirect
golang.org/x/sync v0.3.0 // indirect
golang.org/x/sys v0.9.0 // indirect

10
go.sum
View File

@ -28,8 +28,6 @@ github.com/dchest/uniuri v1.2.0 h1:koIcOUdrTIivZgSLhHQvKgqdWZq5d7KdMEWF1Ud6+5g=
github.com/dchest/uniuri v1.2.0/go.mod h1:fSzm4SLHzNZvWLvWJew423PhAzkpNQYq+uNLq4kxhkY=
github.com/dnaeon/go-vcr v1.1.0/go.mod h1:M7tiix8f0r6mKKJ3Yq/kqU1OYf3MnfmBWVbPx/yU9ko=
github.com/dnaeon/go-vcr v1.2.0/go.mod h1:R4UdLID7HZT3taECzJs4YgbbH6PIGXB6W/sc5OLb6RQ=
github.com/fogleman/gg v1.3.0 h1:/7zJX8F6AaYQc57WQCyN9cAIz+4bCJGO9B+dyW29am8=
github.com/fogleman/gg v1.3.0/go.mod h1:R/bRT+9gY/C5z7JzPU0zXsXHKM4/ayA+zqcVNZzPa1k=
github.com/gabriel-vasile/mimetype v1.4.2 h1:w5qFW6JKBz9Y393Y4q372O9A7cUSequkh1Q7OhCmWKU=
github.com/gabriel-vasile/mimetype v1.4.2/go.mod h1:zApsH/mKG4w07erKIaJPFiX0Tsq9BFQgN3qGY5GnNgA=
github.com/garyburd/redigo v1.6.0/go.mod h1:NR3MbYisc3/PwhQ00EMzDiPmrwpPxAn5GI05/YaO1SY=
@ -91,8 +89,6 @@ github.com/golang-sql/civil v0.0.0-20220223132316-b832511892a9 h1:au07oEsX2xN0kt
github.com/golang-sql/civil v0.0.0-20220223132316-b832511892a9/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0=
github.com/golang-sql/sqlexp v0.1.0 h1:ZCD6MBpcuOVfGVqsEmY5/4FtYiKz6tSyUv9LPEDei6A=
github.com/golang-sql/sqlexp v0.1.0/go.mod h1:J4ad9Vo8ZCWQ2GMrC4UCQy1JpCbwU9m3EOqtpKwwwHI=
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 h1:DACJavvAHhabrF08vX0COfcOBJRhZ8lUbR+ZWIs0Y5g=
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
@ -194,8 +190,6 @@ github.com/pelletier/go-toml/v2 v2.0.8 h1:0ctb6s9mE31h0/lhu+J6OPmVeDxJn+kYnJc2jZ
github.com/pelletier/go-toml/v2 v2.0.8/go.mod h1:vuYfssBdrU2XDZ9bYydBu6t+6a6PYNcZljzZR9VXg+4=
github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8/go.mod h1:HKlIX3XHQyzLZPlr7++PzdhaXEj94dEiJgZDTsxEqUI=
github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/prometheus-community/pro-bing v0.2.0 h1:hyK7yPFndU3LCDwEQJwPQUCjNkp1DGP/VxyzrWfXZUU=
@ -250,8 +244,6 @@ github.com/xhit/go-simple-mail/v2 v2.13.0 h1:OANWU9jHZrVfBkNkvLf8Ww0fexwpQVF/v/5
github.com/xhit/go-simple-mail/v2 v2.13.0/go.mod h1:b7P5ygho6SYE+VIqpxA6QkYfv4teeyG4MKqB3utRu98=
github.com/yeqown/go-qrcode/v2 v2.2.1 h1:Jc1Q916fwC05R8C7mpWDbrT9tyLPaLLKDABoC5XBCe8=
github.com/yeqown/go-qrcode/v2 v2.2.1/go.mod h1:2Qsk2APUCPne0TsRo40DIkI5MYnbzYKCnKGEFWrxd24=
github.com/yeqown/go-qrcode/writer/standard v1.2.1 h1:FMRZiur5yApUIe4fqtqmcdl/XQTZAZWt2DhkPx4VIW0=
github.com/yeqown/go-qrcode/writer/standard v1.2.1/go.mod h1:ZelyDFiVymrauRjUn454iF7bjsabmB1vixkDA5kq2bw=
github.com/yeqown/reedsolomon v1.0.0 h1:x1h/Ej/uJnNu8jaX7GLHBWmZKCAWjEJTetkqaabr4B0=
github.com/yeqown/reedsolomon v1.0.0/go.mod h1:P76zpcn2TCuL0ul1Fso373qHRc69LKwAw/Iy6g1WiiM=
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
@ -267,8 +259,6 @@ golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU
golang.org/x/crypto v0.9.0/go.mod h1:yrmDGqONDYtNj3tH8X9dzUun2m2lzPa9ngI6/RUPGR0=
golang.org/x/crypto v0.10.0 h1:LKqV2xt9+kDzSTfOhx4FrkEBcMrAgHSYgzywV9zcGmM=
golang.org/x/crypto v0.10.0/go.mod h1:o4eNf7Ede1fv+hwOwZsTHl9EsPFO6q6ZvYR8vYfY45I=
golang.org/x/image v0.0.0-20200927104501-e162460cd6b5 h1:QelT11PB4FXiDEXucrfNckHoFxwt8USGY1ajP1ZF5lM=
golang.org/x/image v0.0.0-20200927104501-e162460cd6b5/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/mod v0.10.0 h1:lFO9qtOdlre5W1jxS3r/4szv2/6iXxScdzjoBMXNhYk=

View File

@ -7,7 +7,6 @@ import (
"github.com/h44z/wg-portal/internal/config"
"github.com/h44z/wg-portal/internal/domain"
"github.com/yeqown/go-qrcode/v2"
"github.com/yeqown/go-qrcode/writer/standard"
"io"
)
@ -77,7 +76,11 @@ func (m Manager) GetPeerConfigQrCode(ctx context.Context, id domain.PeerIdentifi
buf := bytes.NewBuffer(nil)
wr := nopCloser{Writer: buf}
qrWriter := standard.NewWithWriter(wr, standard.WithQRWidth(40), standard.WithBuiltinImageEncoder(standard.PNG_FORMAT))
option := Option{
Padding: 8, // padding pixels around the qr code.
BlockSize: 4, // block pixels which represents a bit data.
}
qrWriter := NewCompressedWriter(wr, &option)
err = code.Save(qrWriter)
if err != nil {
return nil, fmt.Errorf("failed to write code for %s: %w", id, err)

View File

@ -0,0 +1,88 @@
package filetemplate
// waiting for https://github.com/yeqown/go-qrcode/pull/85 to get merged
// meanwhile we use our own writer implementation
import (
"image"
"image/color"
"image/png"
"io"
"github.com/yeqown/go-qrcode/v2"
)
type Option struct {
Padding int
BlockSize int
}
// compressedWriter implements issue#69, generating compressed images
// in some special situations, such as, network transferring.
// https://github.com/yeqown/go-qrcode/issues/69
type compressedWriter struct {
fd io.WriteCloser
option *Option
}
var (
backgroundColor = color.Gray{Y: 0xff}
foregroundColor = color.Gray{Y: 0x00}
)
func NewCompressedWriter(writer io.WriteCloser, opt *Option) qrcode.Writer {
return compressedWriter{fd: writer, option: opt}
}
func (w compressedWriter) Write(mat qrcode.Matrix) error {
padding := w.option.Padding
blockWidth := w.option.BlockSize
width := mat.Width()*blockWidth + 2*padding
height := width
img := image.NewPaletted(
image.Rect(0, 0, width, height),
color.Palette([]color.Color{backgroundColor, foregroundColor}),
)
bgColor := uint8(img.Palette.Index(backgroundColor))
fgColor := uint8(img.Palette.Index(foregroundColor))
rectangle := func(x1, y1 int, x2, y2 int, img *image.Paletted, color uint8) {
for x := x1; x < x2; x++ {
for y := y1; y < y2; y++ {
pos := img.PixOffset(x, y)
img.Pix[pos] = color
}
}
}
// background
rectangle(0, 0, width, height, img, bgColor)
mat.Iterate(qrcode.IterDirection_COLUMN, func(x int, y int, v qrcode.QRValue) {
sx := x*blockWidth + padding
sy := y*blockWidth + padding
es := (x+1)*blockWidth + padding
ey := (y+1)*blockWidth + padding
if v.IsSet() {
rectangle(sx, sy, es, ey, img, fgColor)
}
//switch v.IsSet() {
//case false:
// gray = backgroundColor
//default:
// gray = foregroundColor
//}
})
encoder := png.Encoder{CompressionLevel: png.BestCompression}
return encoder.Encode(w.fd, img)
}
func (w compressedWriter) Close() error {
return w.fd.Close()
}