Compare commits
10 Commits
c2e4e2b4f6
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
fbdcde6baf | ||
|
|
c74b4e7749 | ||
|
|
fc385a9e3d | ||
|
|
3c1aa9087c | ||
|
|
2e8be894f6 | ||
|
|
cbfb18ae26 | ||
|
|
95a29c8f05 | ||
|
|
839bc69fbd | ||
|
|
05cd6a8b1b | ||
|
|
5599791533 |
@@ -149,6 +149,8 @@ type PackageConfig struct {
|
||||
// Basename overrides the basename of the package.
|
||||
Basename string `json:",omitempty"`
|
||||
|
||||
Capabilities string `json:",omitempty"`
|
||||
|
||||
// --------------------------------------------------------------------------------
|
||||
// run time package configuration
|
||||
// --------------------------------------------------------------------------------
|
||||
@@ -220,6 +222,11 @@ type Struct struct {
|
||||
// https://www.raspberrypi.com/documentation/computers/config_txt.html
|
||||
BootloaderExtraLines []string `json:",omitempty"`
|
||||
|
||||
// extra lines to append to the bootconf.txt EEPROM section which is read by
|
||||
// the Raspberry Pi bootloader:
|
||||
// https://www.raspberrypi.com/documentation/computers/raspberry-pi.html#raspberry-pi-bootloader-configuration
|
||||
BootloaderExtraEEPROM []string `json:",omitempty"`
|
||||
|
||||
MountDevices []MountDevice `json:",omitempty"`
|
||||
|
||||
// Do not set these manually in config.json, these fields only exist so that
|
||||
|
||||
@@ -60,6 +60,18 @@ var (
|
||||
BootPartitionStartLBA: 32768, // 16MiB from start of disk
|
||||
Slug: "rock64",
|
||||
},
|
||||
"FriendlyElec NanoPi Neo": {
|
||||
// https://linux-sunxi.org/Bootable_SD_card
|
||||
MBROnlyWithoutGPT: true,
|
||||
RootDeviceFiles: []RootFile{
|
||||
// u-boot-sunxi-with-spl.bin is an überpackage that include TPL, SPL, U-Boot and u-boot.dtb.
|
||||
// u-boot can build it as a single file with `make nanopi_neo_defconfig && make u-boot-sunxi-with-spl.bin`
|
||||
// and its easier to work with instead of dealing with separate files.
|
||||
{"u-boot-sunxi-with-spl.bin", 16 * sectorSize, 2032 * sectorSize}, // sectors 16 - 2048
|
||||
},
|
||||
BootPartitionStartLBA: 2048, // 1MiB from start of disk
|
||||
Slug: "nanopi_neo",
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
@@ -4,7 +4,6 @@ import (
|
||||
"crypto/tls"
|
||||
"crypto/x509"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"net/http"
|
||||
"net/url"
|
||||
@@ -32,7 +31,7 @@ func GetTLSHttpClientByTLSFlag(tlsFlag string, tlsInsecure bool, baseUrl *url.UR
|
||||
// Append user specified certificate(s)
|
||||
if tlsFlag != "self-signed" && tlsFlag != "" {
|
||||
usrCert := strings.Split(tlsFlag, ",")[0]
|
||||
certBytes, err := ioutil.ReadFile(usrCert)
|
||||
certBytes, err := os.ReadFile(usrCert)
|
||||
if err != nil {
|
||||
return nil, false, fmt.Errorf("reading user specified certificate %s: %v", usrCert, err)
|
||||
}
|
||||
@@ -44,7 +43,7 @@ func GetTLSHttpClientByTLSFlag(tlsFlag string, tlsInsecure bool, baseUrl *url.UR
|
||||
if _, err := os.Stat(certPath); !os.IsNotExist(err) {
|
||||
foundMatchingCertificate = true
|
||||
log.Printf("Using certificate %s", certPath)
|
||||
certBytes, err := ioutil.ReadFile(certPath)
|
||||
certBytes, err := os.ReadFile(certPath)
|
||||
if err != nil {
|
||||
return nil, false, fmt.Errorf("reading certificate %s: %v", certPath, err)
|
||||
}
|
||||
@@ -84,22 +83,3 @@ func getTLSHTTPClient(trustStore *x509.CertPool, tlsInsecure bool) *http.Client
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func GetRemoteScheme(baseUrl *url.URL) (string, error) {
|
||||
// probe for https redirect, before sending credentials via http
|
||||
probeClient := &http.Client{
|
||||
CheckRedirect: func(*http.Request, []*http.Request) error {
|
||||
return http.ErrUseLastResponse // do not follow redirects
|
||||
},
|
||||
}
|
||||
probeResp, err := probeClient.Get("http://" + baseUrl.Host)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("probing url for https: %v", err)
|
||||
}
|
||||
probeLocation, err := probeResp.Location()
|
||||
if err != nil {
|
||||
// remote did not upgrade us to HTTPS
|
||||
return "http", nil
|
||||
}
|
||||
return probeLocation.Scheme, nil
|
||||
}
|
||||
|
||||
@@ -10,9 +10,9 @@ import (
|
||||
"github.com/gokrazy/internal/updateflag"
|
||||
)
|
||||
|
||||
func For(cfg *config.Struct) (_ *http.Client, foundMatchingCertificate bool, updateBaseURL *url.URL, _ error) {
|
||||
func For(updateVal updateflag.Value, cfg *config.Struct) (_ *http.Client, foundMatchingCertificate bool, updateBaseURL *url.URL, _ error) {
|
||||
schema := "http"
|
||||
certPath, _, err := tlsflag.CertificatePathsFor(cfg.Hostname)
|
||||
certPath, _, err := tlsflag.CertificatePathsFor(cfg.Update.UseTLS, cfg.Hostname)
|
||||
if err != nil {
|
||||
return nil, false, nil, err
|
||||
}
|
||||
@@ -37,12 +37,12 @@ func For(cfg *config.Struct) (_ *http.Client, foundMatchingCertificate bool, upd
|
||||
update.Hostname = cfg.Hostname
|
||||
}
|
||||
|
||||
updateBaseURL, err = updateflag.BaseURL(update.HTTPPort, update.HTTPSPort, schema, update.Hostname, update.HTTPPassword)
|
||||
updateBaseURL, err = updateVal.BaseURL(update.HTTPPort, update.HTTPSPort, schema, update.Hostname, update.HTTPPassword)
|
||||
if err != nil {
|
||||
return nil, false, nil, err
|
||||
}
|
||||
|
||||
hc, fmc, err := GetTLSHttpClientByTLSFlag(tlsflag.GetUseTLS(), tlsflag.GetInsecure(), updateBaseURL)
|
||||
hc, fmc, err := GetTLSHttpClientByTLSFlag(update.UseTLS, cfg.InternalCompatibilityFlags.Insecure, updateBaseURL)
|
||||
if err != nil {
|
||||
return nil, false, nil, fmt.Errorf("getting http client by tls flag: %v", err)
|
||||
}
|
||||
|
||||
@@ -12,11 +12,15 @@ package squashfs
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"cmp"
|
||||
"compress/zlib"
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"slices"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
@@ -115,6 +119,24 @@ type regInodeHeader struct {
|
||||
// Followed by a uint32 array of compressed block sizes.
|
||||
}
|
||||
|
||||
// extFileType
|
||||
type extInodeHeader struct {
|
||||
inodeHeader
|
||||
|
||||
// full byte offset from the start of the file system, e.g. 96 for first
|
||||
// file contents. Not using fragments limits us to 2^32-1-96 (≈ 4GiB) bytes
|
||||
// of file contents.
|
||||
StartBlock uint64
|
||||
FileSize uint64
|
||||
Sparse uint64
|
||||
Links uint32
|
||||
Fragment uint32
|
||||
Offset uint32
|
||||
xattr uint32
|
||||
|
||||
// Followed by a uint32 array of compressed block sizes.
|
||||
}
|
||||
|
||||
// symlinkType
|
||||
type symlinkInodeHeader struct {
|
||||
inodeHeader
|
||||
@@ -179,6 +201,24 @@ type dirEntry struct {
|
||||
// Followed by a byte array of Size bytes.
|
||||
}
|
||||
|
||||
type xattr struct {
|
||||
Type uint16
|
||||
// KeySize uint16
|
||||
Key string
|
||||
// ValueSize uint16
|
||||
Value []byte
|
||||
}
|
||||
|
||||
func (x xattr) Equals(xattr xattr) bool {
|
||||
return x.Type == xattr.Type && x.Key == xattr.Key && bytes.Equal(x.Value, xattr.Value)
|
||||
}
|
||||
|
||||
type xattrOffsets struct {
|
||||
Offset uint64 // Stored similar to an Inode
|
||||
Count uint32
|
||||
Size uint32
|
||||
}
|
||||
|
||||
func writeIdTable(w io.WriteSeeker, ids []uint32) (start int64, err error) {
|
||||
metaOff, err := w.Seek(0, io.SeekCurrent)
|
||||
if err != nil {
|
||||
@@ -202,6 +242,119 @@ func writeIdTable(w io.WriteSeeker, ids []uint32) (start int64, err error) {
|
||||
return off, binary.Write(w, binary.LittleEndian, metaOff)
|
||||
}
|
||||
|
||||
func writeXattr(w io.Writer, xattr xattr) error {
|
||||
if err := binary.Write(w, binary.LittleEndian, xattr.Type); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := binary.Write(w, binary.LittleEndian, uint16(len(xattr.Key))); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := binary.Write(w, binary.LittleEndian, []byte(xattr.Key)); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := binary.Write(w, binary.LittleEndian, uint32(len(xattr.Value))); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := binary.Write(w, binary.LittleEndian, xattr.Value); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func writeXattrTable(w io.WriteSeeker, xattrGroups [][]xattr) ([]xattrOffsets, error) {
|
||||
var (
|
||||
buf bytes.Buffer
|
||||
err error
|
||||
groupOffsets []xattrOffsets
|
||||
)
|
||||
for _, xattrs := range xattrGroups {
|
||||
start := buf.Len()
|
||||
for _, xattr := range xattrs {
|
||||
if err = writeXattr(&buf, xattr); err != nil {
|
||||
return []xattrOffsets{}, err
|
||||
}
|
||||
}
|
||||
groupOffsets = append(groupOffsets, xattrOffsets{
|
||||
Offset: uint64(0<<16 | start), // We only write one metadata block so index is always 0
|
||||
Count: uint32(len(xattrs)),
|
||||
Size: uint32(buf.Len() - start),
|
||||
})
|
||||
}
|
||||
|
||||
if buf.Len() > metadataBlockSize {
|
||||
return []xattrOffsets{}, fmt.Errorf("too many xattrs defined")
|
||||
}
|
||||
|
||||
if err := binary.Write(w, binary.LittleEndian, uint16(buf.Len())|0x8000); err != nil {
|
||||
return []xattrOffsets{}, err
|
||||
}
|
||||
if _, err := io.Copy(w, &buf); err != nil {
|
||||
return []xattrOffsets{}, err
|
||||
}
|
||||
return groupOffsets, nil
|
||||
}
|
||||
|
||||
func writeXattrIdTable(w io.WriteSeeker, xattrGroups [][]xattr) (start int64, err error) {
|
||||
if len(xattrGroups) == 0 {
|
||||
// Sanity check as the linux kernel would not load the filesystem if there isn't a value here
|
||||
return 0, fmt.Errorf("xattrGroups must have atleast one value")
|
||||
}
|
||||
kvOff, err := w.Seek(0, io.SeekCurrent)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
groupOffsets, err := writeXattrTable(w, xattrGroups)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
metaOff, err := w.Seek(0, io.SeekCurrent)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
var buf bytes.Buffer
|
||||
if err := binary.Write(&buf, binary.LittleEndian, groupOffsets); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
if buf.Len() > metadataBlockSize {
|
||||
return 0, fmt.Errorf("too many xattrs defined")
|
||||
}
|
||||
|
||||
if err := binary.Write(w, binary.LittleEndian, uint16(buf.Len())|0x8000); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
if _, err := io.Copy(w, &buf); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
off, err := w.Seek(0, io.SeekCurrent)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
err = binary.Write(w, binary.LittleEndian, uint64(kvOff))
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
err = binary.Write(w, binary.LittleEndian, uint32(len(xattrGroups)))
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
err = binary.Write(w, binary.LittleEndian, uint32(0))
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
err = binary.Write(w, binary.LittleEndian, uint64(metaOff))
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
return off, nil
|
||||
}
|
||||
|
||||
type fullDirEntry struct {
|
||||
startBlock uint32
|
||||
offset uint16
|
||||
@@ -228,6 +381,7 @@ type Writer struct {
|
||||
sb superblock
|
||||
inodeBuf bytes.Buffer
|
||||
dirBuf bytes.Buffer
|
||||
xattrGroups [][]xattr
|
||||
|
||||
writeInodeNumTo map[string][]int64
|
||||
}
|
||||
@@ -325,6 +479,9 @@ type file struct {
|
||||
modTime time.Time
|
||||
mode os.FileMode
|
||||
|
||||
// xattrs list of xattrs to attach to this file
|
||||
xattrs []xattr
|
||||
|
||||
// buf accumulates at least dataBlockSize bytes, at which point a new block
|
||||
// is being written.
|
||||
buf bytes.Buffer
|
||||
@@ -352,11 +509,36 @@ func (d *Directory) Directory(name string, modTime time.Time) *Directory {
|
||||
|
||||
// File creates a file with the specified name, modTime and mode. The returned
|
||||
// io.WriterCloser must be closed after writing the file.
|
||||
func (d *Directory) File(name string, modTime time.Time, mode os.FileMode) (io.WriteCloser, error) {
|
||||
func (d *Directory) File(name string, modTime time.Time, mode os.FileMode, xattrs map[string][]byte) (io.WriteCloser, error) {
|
||||
off, err := d.w.w.Seek(0, io.SeekCurrent)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var xattrlist []xattr
|
||||
if len(xattrs) > 0 {
|
||||
for key, value := range xattrs {
|
||||
var (
|
||||
keyType uint16
|
||||
)
|
||||
|
||||
keys := strings.SplitN(key, ".", 2)
|
||||
switch keys[0] {
|
||||
case "user":
|
||||
keyType = 0
|
||||
case "trusted":
|
||||
keyType = 1
|
||||
case "security":
|
||||
keyType = 2
|
||||
default:
|
||||
return nil, fmt.Errorf("Invalid xattr key: %s, key must start with security, trusted or user", key)
|
||||
}
|
||||
xattrlist = append(xattrlist, xattr{
|
||||
Type: keyType,
|
||||
Key: keys[1],
|
||||
Value: value,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// zlib.BestSpeed results in only a 2x slow-down over no compression
|
||||
// (compared to >4x slow-down with DefaultCompression), but generates
|
||||
@@ -374,6 +556,7 @@ func (d *Directory) File(name string, modTime time.Time, mode os.FileMode) (io.W
|
||||
mode: mode,
|
||||
compBuf: bytes.NewBuffer(make([]byte, dataBlockSize)),
|
||||
zlibWriter: zw,
|
||||
xattrs: xattrlist,
|
||||
}, nil
|
||||
}
|
||||
|
||||
@@ -605,7 +788,28 @@ func (f *file) Close() error {
|
||||
|
||||
startBlock := f.w.inodeBuf.Len() / metadataBlockSize
|
||||
offset := f.w.inodeBuf.Len() - startBlock*metadataBlockSize
|
||||
|
||||
if len(f.xattrs) > 0 {
|
||||
extinode := extInodeHeader{
|
||||
inodeHeader: inodeHeader{
|
||||
InodeType: lregType,
|
||||
Mode: uint16(f.mode),
|
||||
Uid: 0,
|
||||
Gid: 0,
|
||||
Mtime: int32(f.modTime.Unix()),
|
||||
InodeNumber: f.w.sb.Inodes + 1,
|
||||
},
|
||||
StartBlock: uint64(f.off), // TODO(later): check for overflow
|
||||
FileSize: uint64(f.size),
|
||||
Sparse: 0,
|
||||
Links: 1, // We don't support hardlinks at this time
|
||||
Fragment: invalidFragment,
|
||||
Offset: 0,
|
||||
xattr: f.w.addXattrs(f.xattrs),
|
||||
}
|
||||
if err := binary.Write(&f.w.inodeBuf, binary.LittleEndian, extinode); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
if err := binary.Write(&f.w.inodeBuf, binary.LittleEndian, regInodeHeader{
|
||||
inodeHeader: inodeHeader{
|
||||
InodeType: fileType,
|
||||
@@ -622,6 +826,7 @@ func (f *file) Close() error {
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if err := binary.Write(&f.w.inodeBuf, binary.LittleEndian, f.blocksizes); err != nil {
|
||||
return err
|
||||
@@ -711,8 +916,14 @@ func (w *Writer) Flush() error {
|
||||
}
|
||||
w.sb.IdTableStart = idTableStart
|
||||
|
||||
// (9) xattr table omitted
|
||||
|
||||
// (9) xattr table must be omitted if there are no xattrs
|
||||
if len(w.xattrGroups) != 0 {
|
||||
xattrIdTableStart, err := writeXattrIdTable(w.w, w.xattrGroups)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
w.sb.XattrIdTableStart = xattrIdTableStart
|
||||
}
|
||||
off, err = w.w.Seek(0, io.SeekCurrent)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -734,3 +945,31 @@ func (w *Writer) Flush() error {
|
||||
|
||||
return binary.Write(w.w, binary.LittleEndian, &w.sb)
|
||||
}
|
||||
|
||||
func xattrCompare(a xattr, b xattr) int {
|
||||
return cmp.Or(
|
||||
cmp.Compare(a.Type, b.Type),
|
||||
cmp.Compare(a.Key, b.Key),
|
||||
bytes.Compare(a.Value, b.Value),
|
||||
)
|
||||
}
|
||||
|
||||
func (w *Writer) addXattrs(xattrs []xattr) uint32 {
|
||||
// Does trivial xattr de-duplication. More complicated de-duplication is possible if space is a concern
|
||||
slices.SortFunc(xattrs, xattrCompare)
|
||||
xattrGroup:
|
||||
for i, group := range w.xattrGroups {
|
||||
if len(group) != len(xattrs) {
|
||||
continue
|
||||
}
|
||||
for x, xattr := range xattrs {
|
||||
if !xattr.Equals(group[x]) {
|
||||
continue xattrGroup
|
||||
}
|
||||
}
|
||||
return uint32(i)
|
||||
}
|
||||
i := len(w.xattrGroups)
|
||||
w.xattrGroups = append(w.xattrGroups, xattrs)
|
||||
return uint32(i)
|
||||
}
|
||||
|
||||
@@ -43,7 +43,7 @@ func TestUnsquashfs(t *testing.T) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
ff, err := w.Root.File("hellö wörld", time.Now(), 0o444 /* u=r,g=r,o=r */)
|
||||
ff, err := w.Root.File("hellö wörld", time.Now(), 0o444 /* u=r,g=r,o=r */, map[string][]byte{})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -54,7 +54,7 @@ func TestUnsquashfs(t *testing.T) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
ff, err = w.Root.File("leer", time.Now(), 0o444 /* u=r,g=r,o=r */)
|
||||
ff, err = w.Root.File("leer", time.Now(), 0o444 /* u=r,g=r,o=r */, map[string][]byte{})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -62,7 +62,7 @@ func TestUnsquashfs(t *testing.T) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
ff, err = w.Root.File("second file", time.Now(), 0o555 /* u=rx,g=rx,o=rx */)
|
||||
ff, err = w.Root.File("second file", time.Now(), 0o555 /* u=rx,g=rx,o=rx */, map[string][]byte{})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -80,7 +80,7 @@ func TestUnsquashfs(t *testing.T) {
|
||||
subdir := w.Root.Directory("subdir", time.Now())
|
||||
|
||||
subsubdir := subdir.Directory("deep", time.Now())
|
||||
ff, err = subsubdir.File("yo", time.Now(), 0o444 /* u=r,g=r,o=r */)
|
||||
ff, err = subsubdir.File("yo", time.Now(), 0o444 /* u=r,g=r,o=r */, map[string][]byte{})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -96,7 +96,7 @@ func TestUnsquashfs(t *testing.T) {
|
||||
|
||||
// TODO: write another file in subdir now, will result in invalid parent inode
|
||||
|
||||
ff, err = subdir.File("third file (in subdir)", time.Now(), 0o444 /* u=r,g=r,o=r */)
|
||||
ff, err = subdir.File("third file (in subdir)", time.Now(), 0o444 /* u=r,g=r,o=r */, map[string][]byte{})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -110,7 +110,7 @@ func TestUnsquashfs(t *testing.T) {
|
||||
if err := subdir.Flush(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
ff, err = w.Root.File("testbin", time.Now(), 0o555 /* u=rx,g=rx,o=rx */)
|
||||
ff, err = w.Root.File("testbin", time.Now(), 0o555 /* u=rx,g=rx,o=rx */, map[string][]byte{})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package tlsflag
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
@@ -10,30 +9,6 @@ import (
|
||||
"github.com/gokrazy/internal/config"
|
||||
)
|
||||
|
||||
var (
|
||||
useTLS string
|
||||
insecure bool
|
||||
)
|
||||
|
||||
func RegisterFlags(fs *flag.FlagSet) {
|
||||
fs.StringVar(&useTLS,
|
||||
"tls",
|
||||
"",
|
||||
`TLS certificate for the web interface (-tls=<certificate or full chain path>,<private key path>).
|
||||
Use -tls=self-signed to generate a self-signed RSA4096 certificate using the hostname specified with -hostname. In this case, the certificate and key will be placed in your local config folder (on Linux: ~/.config/gokrazy/<hostname>/).
|
||||
WARNING: When reusing a hostname, no new certificate will be generated and the stored one will be used.
|
||||
When updating a running instance, the specified certificate will be used to verify the connection. Otherwise the updater will load the hostname-specific certificate from your local config folder in addition to the system trust store.
|
||||
You can also create your own certificate-key-pair (e.g. by using https://github.com/FiloSottile/mkcert) and place them into your local config folder.`)
|
||||
|
||||
fs.BoolVar(&insecure, "insecure",
|
||||
false,
|
||||
"Ignore TLS stripping detection.")
|
||||
}
|
||||
|
||||
func Insecure() bool {
|
||||
return insecure
|
||||
}
|
||||
|
||||
type ErrNotYetCreated struct {
|
||||
HostConfigPath string
|
||||
CertPath string
|
||||
@@ -44,7 +19,7 @@ func (e *ErrNotYetCreated) Error() string {
|
||||
return "self-signed certificate not yet created"
|
||||
}
|
||||
|
||||
func CertificatePathsFor(hostname string) (certPath string, keyPath string, _ error) {
|
||||
func CertificatePathsFor(useTLS, hostname string) (certPath string, keyPath string, _ error) {
|
||||
hostConfigPath := config.HostnameSpecific(hostname)
|
||||
certPath = filepath.Join(string(hostConfigPath), "cert.pem")
|
||||
keyPath = filepath.Join(string(hostConfigPath), "key.pem")
|
||||
@@ -95,11 +70,3 @@ func CertificatePathsFor(hostname string) (certPath string, keyPath string, _ er
|
||||
}
|
||||
return certPath, keyPath, nil
|
||||
}
|
||||
|
||||
func GetUseTLS() string { return useTLS }
|
||||
|
||||
func SetUseTLS(s string) { useTLS = s }
|
||||
|
||||
func GetInsecure() bool { return insecure }
|
||||
|
||||
func SetInsecure(b bool) { insecure = b }
|
||||
|
||||
@@ -1,48 +1,29 @@
|
||||
package updateflag
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"net/url"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/spf13/pflag"
|
||||
)
|
||||
|
||||
var update string
|
||||
|
||||
func registerFlags(fs interface {
|
||||
StringVar(*string, string, string, string)
|
||||
}, updateFlagName string) {
|
||||
fs.StringVar(&update,
|
||||
updateFlagName,
|
||||
os.Getenv("GOKRAZY_UPDATE"),
|
||||
`URL of a gokrazy installation (e.g. http://gokrazy:mypassword@myhostname/) to work with. The special value "yes" uses the stored password and -hostname value to construct the URL`)
|
||||
type Value struct {
|
||||
Update string
|
||||
}
|
||||
|
||||
func RegisterFlags(fs *flag.FlagSet, updateFlagName string) {
|
||||
registerFlags(fs, updateFlagName)
|
||||
}
|
||||
|
||||
func RegisterPflags(fs *pflag.FlagSet, updateFlagName string) {
|
||||
registerFlags(fs, updateFlagName)
|
||||
}
|
||||
|
||||
func GetUpdateTarget(hostname string) (defaultPassword, updateHostname string) {
|
||||
if update == "" {
|
||||
func (v Value) GetUpdateTarget(hostname string) (defaultPassword, updateHostname string) {
|
||||
if v.Update == "" {
|
||||
// -update not set
|
||||
return "", hostname
|
||||
}
|
||||
if update == "yes" {
|
||||
if v.Update == "yes" {
|
||||
// -update=yes
|
||||
return "", hostname
|
||||
}
|
||||
if strings.HasPrefix(update, ":") {
|
||||
if strings.HasPrefix(v.Update, ":") {
|
||||
// port number syntax, e.g. -update=:2080
|
||||
return "", hostname
|
||||
}
|
||||
// -update=<url> syntax
|
||||
u, err := url.Parse(update)
|
||||
u, err := url.Parse(v.Update)
|
||||
if err != nil {
|
||||
return "", hostname
|
||||
}
|
||||
@@ -50,10 +31,10 @@ func GetUpdateTarget(hostname string) (defaultPassword, updateHostname string) {
|
||||
return defaultPassword, u.Host
|
||||
}
|
||||
|
||||
func BaseURL(httpPort, httpsPort, schema, hostname, pw string) (*url.URL, error) {
|
||||
if update != "yes" && !strings.HasPrefix(update, ":") {
|
||||
func (v Value) BaseURL(httpPort, httpsPort, schema, hostname, pw string) (*url.URL, error) {
|
||||
if v.Update != "yes" && !strings.HasPrefix(v.Update, ":") {
|
||||
// already fully qualified, nothing to add
|
||||
return url.Parse(update)
|
||||
return url.Parse(v.Update)
|
||||
}
|
||||
port := httpPort
|
||||
defaultPort := "80"
|
||||
@@ -61,21 +42,13 @@ func BaseURL(httpPort, httpsPort, schema, hostname, pw string) (*url.URL, error)
|
||||
port = httpsPort
|
||||
defaultPort = "443"
|
||||
}
|
||||
if strings.HasPrefix(update, ":") {
|
||||
port = strings.TrimPrefix(update, ":")
|
||||
if strings.HasPrefix(v.Update, ":") {
|
||||
port = strings.TrimPrefix(v.Update, ":")
|
||||
}
|
||||
update = schema + "://gokrazy:" + pw + "@" + hostname
|
||||
v.Update = schema + "://gokrazy:" + pw + "@" + hostname
|
||||
if port != defaultPort {
|
||||
update += ":" + port
|
||||
v.Update += ":" + port
|
||||
}
|
||||
update += "/"
|
||||
return url.Parse(update)
|
||||
v.Update += "/"
|
||||
return url.Parse(v.Update)
|
||||
}
|
||||
|
||||
func NewInstallation() bool {
|
||||
return update == ""
|
||||
}
|
||||
|
||||
func SetUpdate(u string) { update = u }
|
||||
|
||||
func GetUpdate() string { return update }
|
||||
|
||||
@@ -47,8 +47,9 @@ func TestBaseURL(t *testing.T) {
|
||||
},
|
||||
} {
|
||||
t.Run(tt.desc, func(t *testing.T) {
|
||||
updateflag.SetUpdate("yes")
|
||||
got, err := updateflag.BaseURL(tt.HTTPPort, tt.HTTPSPort, tt.Schema, tt.Hostname, tt.Password)
|
||||
got, err := updateflag.Value{
|
||||
Update: "yes",
|
||||
}.BaseURL(tt.HTTPPort, tt.HTTPSPort, tt.Schema, tt.Hostname, tt.Password)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user