go-gemini/tofu/tofu.go

331 lines
6.5 KiB
Go
Raw Normal View History

2021-01-10 21:44:32 +00:00
// Package tofu implements trust on first use using hosts and fingerprints.
package tofu
2020-09-25 22:53:20 +00:00
import (
"bufio"
tofu: Refactor This commit changes underlying file handling and known hosts parsing. A known hosts file opened through Load() never closed the underlying file. During known hosts parsing most errors were unchecked, or just led to the line being skipped. I removed the KnownHosts type, which didn't really have a role after the refactor. The embedding of KnownHosts in KnownHosts file has been removed as it also leaked the map unprotected by the mutex. The Fingerprint type is now KnownHost and has taken over the responsibility of marshalling and unmarshalling. SetOutput now takes a WriteCloser so that we can close the underlying writer when it's replaced, or when it's explicitly closed through the new Close() function. KnownHostsFile.Add() now also writes the known host to the output if set. I think that makes sense expectation-wise for the type. Turned WriteAll() into WriteTo() to conform with the io.WriterTo interface. Load() is now Open() to better reflect the fact that a file is opened, and kept open. It can now also return errors from the parsing process. The parser does a lot more error checking, and this might be an area where I've changed a desired behaviour as invalid entries no longer are ignored, but aborts the parsing process. That could be changed to a warning, or some kind of parsing feedback. I added KnownHostsFile.TOFU() to fill the developer experience gap that was left after the client no longer knows about KnownHostsFile. It implements a basic non-interactive TOFU flow.
2021-01-13 21:33:48 +00:00
"bytes"
2020-09-25 22:53:20 +00:00
"crypto/sha512"
tofu: Refactor This commit changes underlying file handling and known hosts parsing. A known hosts file opened through Load() never closed the underlying file. During known hosts parsing most errors were unchecked, or just led to the line being skipped. I removed the KnownHosts type, which didn't really have a role after the refactor. The embedding of KnownHosts in KnownHosts file has been removed as it also leaked the map unprotected by the mutex. The Fingerprint type is now KnownHost and has taken over the responsibility of marshalling and unmarshalling. SetOutput now takes a WriteCloser so that we can close the underlying writer when it's replaced, or when it's explicitly closed through the new Close() function. KnownHostsFile.Add() now also writes the known host to the output if set. I think that makes sense expectation-wise for the type. Turned WriteAll() into WriteTo() to conform with the io.WriterTo interface. Load() is now Open() to better reflect the fact that a file is opened, and kept open. It can now also return errors from the parsing process. The parser does a lot more error checking, and this might be an area where I've changed a desired behaviour as invalid entries no longer are ignored, but aborts the parsing process. That could be changed to a warning, or some kind of parsing feedback. I added KnownHostsFile.TOFU() to fill the developer experience gap that was left after the client no longer knows about KnownHostsFile. It implements a basic non-interactive TOFU flow.
2021-01-13 21:33:48 +00:00
"crypto/x509"
"errors"
2020-09-25 22:53:20 +00:00
"fmt"
"io"
2020-09-26 03:06:54 +00:00
"os"
2020-11-06 03:30:13 +00:00
"strconv"
2020-09-25 22:53:20 +00:00
"strings"
2020-12-17 22:07:00 +00:00
"sync"
2020-11-09 17:04:53 +00:00
"time"
2020-09-25 22:53:20 +00:00
)
2021-01-14 19:15:08 +00:00
// HostsFile represents a list of known hosts optionally loaded from a file.
// The zero value for HostsFile represents an empty list ready to use.
//
2021-01-14 19:15:08 +00:00
// HostsFile is safe for concurrent use by multiple goroutines.
type HostsFile struct {
hosts map[string]Host
writer *bufio.Writer
tofu: Refactor This commit changes underlying file handling and known hosts parsing. A known hosts file opened through Load() never closed the underlying file. During known hosts parsing most errors were unchecked, or just led to the line being skipped. I removed the KnownHosts type, which didn't really have a role after the refactor. The embedding of KnownHosts in KnownHosts file has been removed as it also leaked the map unprotected by the mutex. The Fingerprint type is now KnownHost and has taken over the responsibility of marshalling and unmarshalling. SetOutput now takes a WriteCloser so that we can close the underlying writer when it's replaced, or when it's explicitly closed through the new Close() function. KnownHostsFile.Add() now also writes the known host to the output if set. I think that makes sense expectation-wise for the type. Turned WriteAll() into WriteTo() to conform with the io.WriterTo interface. Load() is now Open() to better reflect the fact that a file is opened, and kept open. It can now also return errors from the parsing process. The parser does a lot more error checking, and this might be an area where I've changed a desired behaviour as invalid entries no longer are ignored, but aborts the parsing process. That could be changed to a warning, or some kind of parsing feedback. I added KnownHostsFile.TOFU() to fill the developer experience gap that was left after the client no longer knows about KnownHostsFile. It implements a basic non-interactive TOFU flow.
2021-01-13 21:33:48 +00:00
closer io.Closer
mu sync.RWMutex
2020-11-09 17:26:08 +00:00
}
// SetOutput sets the output to which new known hosts will be written to.
2021-01-14 19:15:08 +00:00
func (k *HostsFile) SetOutput(w io.WriteCloser) error {
k.mu.Lock()
defer k.mu.Unlock()
tofu: Refactor This commit changes underlying file handling and known hosts parsing. A known hosts file opened through Load() never closed the underlying file. During known hosts parsing most errors were unchecked, or just led to the line being skipped. I removed the KnownHosts type, which didn't really have a role after the refactor. The embedding of KnownHosts in KnownHosts file has been removed as it also leaked the map unprotected by the mutex. The Fingerprint type is now KnownHost and has taken over the responsibility of marshalling and unmarshalling. SetOutput now takes a WriteCloser so that we can close the underlying writer when it's replaced, or when it's explicitly closed through the new Close() function. KnownHostsFile.Add() now also writes the known host to the output if set. I think that makes sense expectation-wise for the type. Turned WriteAll() into WriteTo() to conform with the io.WriterTo interface. Load() is now Open() to better reflect the fact that a file is opened, and kept open. It can now also return errors from the parsing process. The parser does a lot more error checking, and this might be an area where I've changed a desired behaviour as invalid entries no longer are ignored, but aborts the parsing process. That could be changed to a warning, or some kind of parsing feedback. I added KnownHostsFile.TOFU() to fill the developer experience gap that was left after the client no longer knows about KnownHostsFile. It implements a basic non-interactive TOFU flow.
2021-01-13 21:33:48 +00:00
2021-01-14 19:15:08 +00:00
if k.writer != nil {
tofu: Refactor This commit changes underlying file handling and known hosts parsing. A known hosts file opened through Load() never closed the underlying file. During known hosts parsing most errors were unchecked, or just led to the line being skipped. I removed the KnownHosts type, which didn't really have a role after the refactor. The embedding of KnownHosts in KnownHosts file has been removed as it also leaked the map unprotected by the mutex. The Fingerprint type is now KnownHost and has taken over the responsibility of marshalling and unmarshalling. SetOutput now takes a WriteCloser so that we can close the underlying writer when it's replaced, or when it's explicitly closed through the new Close() function. KnownHostsFile.Add() now also writes the known host to the output if set. I think that makes sense expectation-wise for the type. Turned WriteAll() into WriteTo() to conform with the io.WriterTo interface. Load() is now Open() to better reflect the fact that a file is opened, and kept open. It can now also return errors from the parsing process. The parser does a lot more error checking, and this might be an area where I've changed a desired behaviour as invalid entries no longer are ignored, but aborts the parsing process. That could be changed to a warning, or some kind of parsing feedback. I added KnownHostsFile.TOFU() to fill the developer experience gap that was left after the client no longer knows about KnownHostsFile. It implements a basic non-interactive TOFU flow.
2021-01-13 21:33:48 +00:00
err := k.closer.Close()
if err != nil {
return fmt.Errorf("failed to close previous output: %w", err)
}
}
2021-01-14 19:15:08 +00:00
k.writer = bufio.NewWriter(w)
tofu: Refactor This commit changes underlying file handling and known hosts parsing. A known hosts file opened through Load() never closed the underlying file. During known hosts parsing most errors were unchecked, or just led to the line being skipped. I removed the KnownHosts type, which didn't really have a role after the refactor. The embedding of KnownHosts in KnownHosts file has been removed as it also leaked the map unprotected by the mutex. The Fingerprint type is now KnownHost and has taken over the responsibility of marshalling and unmarshalling. SetOutput now takes a WriteCloser so that we can close the underlying writer when it's replaced, or when it's explicitly closed through the new Close() function. KnownHostsFile.Add() now also writes the known host to the output if set. I think that makes sense expectation-wise for the type. Turned WriteAll() into WriteTo() to conform with the io.WriterTo interface. Load() is now Open() to better reflect the fact that a file is opened, and kept open. It can now also return errors from the parsing process. The parser does a lot more error checking, and this might be an area where I've changed a desired behaviour as invalid entries no longer are ignored, but aborts the parsing process. That could be changed to a warning, or some kind of parsing feedback. I added KnownHostsFile.TOFU() to fill the developer experience gap that was left after the client no longer knows about KnownHostsFile. It implements a basic non-interactive TOFU flow.
2021-01-13 21:33:48 +00:00
k.closer = w
return nil
2020-09-26 03:06:54 +00:00
}
tofu: Refactor This commit changes underlying file handling and known hosts parsing. A known hosts file opened through Load() never closed the underlying file. During known hosts parsing most errors were unchecked, or just led to the line being skipped. I removed the KnownHosts type, which didn't really have a role after the refactor. The embedding of KnownHosts in KnownHosts file has been removed as it also leaked the map unprotected by the mutex. The Fingerprint type is now KnownHost and has taken over the responsibility of marshalling and unmarshalling. SetOutput now takes a WriteCloser so that we can close the underlying writer when it's replaced, or when it's explicitly closed through the new Close() function. KnownHostsFile.Add() now also writes the known host to the output if set. I think that makes sense expectation-wise for the type. Turned WriteAll() into WriteTo() to conform with the io.WriterTo interface. Load() is now Open() to better reflect the fact that a file is opened, and kept open. It can now also return errors from the parsing process. The parser does a lot more error checking, and this might be an area where I've changed a desired behaviour as invalid entries no longer are ignored, but aborts the parsing process. That could be changed to a warning, or some kind of parsing feedback. I added KnownHostsFile.TOFU() to fill the developer experience gap that was left after the client no longer knows about KnownHostsFile. It implements a basic non-interactive TOFU flow.
2021-01-13 21:33:48 +00:00
// Close closes the output.
2021-01-14 19:15:08 +00:00
func (k *HostsFile) Close() error {
k.mu.Lock()
defer k.mu.Unlock()
tofu: Refactor This commit changes underlying file handling and known hosts parsing. A known hosts file opened through Load() never closed the underlying file. During known hosts parsing most errors were unchecked, or just led to the line being skipped. I removed the KnownHosts type, which didn't really have a role after the refactor. The embedding of KnownHosts in KnownHosts file has been removed as it also leaked the map unprotected by the mutex. The Fingerprint type is now KnownHost and has taken over the responsibility of marshalling and unmarshalling. SetOutput now takes a WriteCloser so that we can close the underlying writer when it's replaced, or when it's explicitly closed through the new Close() function. KnownHostsFile.Add() now also writes the known host to the output if set. I think that makes sense expectation-wise for the type. Turned WriteAll() into WriteTo() to conform with the io.WriterTo interface. Load() is now Open() to better reflect the fact that a file is opened, and kept open. It can now also return errors from the parsing process. The parser does a lot more error checking, and this might be an area where I've changed a desired behaviour as invalid entries no longer are ignored, but aborts the parsing process. That could be changed to a warning, or some kind of parsing feedback. I added KnownHostsFile.TOFU() to fill the developer experience gap that was left after the client no longer knows about KnownHostsFile. It implements a basic non-interactive TOFU flow.
2021-01-13 21:33:48 +00:00
2021-01-14 19:15:08 +00:00
if k.writer == nil {
tofu: Refactor This commit changes underlying file handling and known hosts parsing. A known hosts file opened through Load() never closed the underlying file. During known hosts parsing most errors were unchecked, or just led to the line being skipped. I removed the KnownHosts type, which didn't really have a role after the refactor. The embedding of KnownHosts in KnownHosts file has been removed as it also leaked the map unprotected by the mutex. The Fingerprint type is now KnownHost and has taken over the responsibility of marshalling and unmarshalling. SetOutput now takes a WriteCloser so that we can close the underlying writer when it's replaced, or when it's explicitly closed through the new Close() function. KnownHostsFile.Add() now also writes the known host to the output if set. I think that makes sense expectation-wise for the type. Turned WriteAll() into WriteTo() to conform with the io.WriterTo interface. Load() is now Open() to better reflect the fact that a file is opened, and kept open. It can now also return errors from the parsing process. The parser does a lot more error checking, and this might be an area where I've changed a desired behaviour as invalid entries no longer are ignored, but aborts the parsing process. That could be changed to a warning, or some kind of parsing feedback. I added KnownHostsFile.TOFU() to fill the developer experience gap that was left after the client no longer knows about KnownHostsFile. It implements a basic non-interactive TOFU flow.
2021-01-13 21:33:48 +00:00
return nil
2020-11-09 17:04:53 +00:00
}
tofu: Refactor This commit changes underlying file handling and known hosts parsing. A known hosts file opened through Load() never closed the underlying file. During known hosts parsing most errors were unchecked, or just led to the line being skipped. I removed the KnownHosts type, which didn't really have a role after the refactor. The embedding of KnownHosts in KnownHosts file has been removed as it also leaked the map unprotected by the mutex. The Fingerprint type is now KnownHost and has taken over the responsibility of marshalling and unmarshalling. SetOutput now takes a WriteCloser so that we can close the underlying writer when it's replaced, or when it's explicitly closed through the new Close() function. KnownHostsFile.Add() now also writes the known host to the output if set. I think that makes sense expectation-wise for the type. Turned WriteAll() into WriteTo() to conform with the io.WriterTo interface. Load() is now Open() to better reflect the fact that a file is opened, and kept open. It can now also return errors from the parsing process. The parser does a lot more error checking, and this might be an area where I've changed a desired behaviour as invalid entries no longer are ignored, but aborts the parsing process. That could be changed to a warning, or some kind of parsing feedback. I added KnownHostsFile.TOFU() to fill the developer experience gap that was left after the client no longer knows about KnownHostsFile. It implements a basic non-interactive TOFU flow.
2021-01-13 21:33:48 +00:00
err := k.closer.Close()
if err != nil {
return err
}
2021-01-14 19:15:08 +00:00
k.writer = nil
tofu: Refactor This commit changes underlying file handling and known hosts parsing. A known hosts file opened through Load() never closed the underlying file. During known hosts parsing most errors were unchecked, or just led to the line being skipped. I removed the KnownHosts type, which didn't really have a role after the refactor. The embedding of KnownHosts in KnownHosts file has been removed as it also leaked the map unprotected by the mutex. The Fingerprint type is now KnownHost and has taken over the responsibility of marshalling and unmarshalling. SetOutput now takes a WriteCloser so that we can close the underlying writer when it's replaced, or when it's explicitly closed through the new Close() function. KnownHostsFile.Add() now also writes the known host to the output if set. I think that makes sense expectation-wise for the type. Turned WriteAll() into WriteTo() to conform with the io.WriterTo interface. Load() is now Open() to better reflect the fact that a file is opened, and kept open. It can now also return errors from the parsing process. The parser does a lot more error checking, and this might be an area where I've changed a desired behaviour as invalid entries no longer are ignored, but aborts the parsing process. That could be changed to a warning, or some kind of parsing feedback. I added KnownHostsFile.TOFU() to fill the developer experience gap that was left after the client no longer knows about KnownHostsFile. It implements a basic non-interactive TOFU flow.
2021-01-13 21:33:48 +00:00
k.closer = nil
return nil
2020-11-09 17:04:53 +00:00
}
tofu: Refactor This commit changes underlying file handling and known hosts parsing. A known hosts file opened through Load() never closed the underlying file. During known hosts parsing most errors were unchecked, or just led to the line being skipped. I removed the KnownHosts type, which didn't really have a role after the refactor. The embedding of KnownHosts in KnownHosts file has been removed as it also leaked the map unprotected by the mutex. The Fingerprint type is now KnownHost and has taken over the responsibility of marshalling and unmarshalling. SetOutput now takes a WriteCloser so that we can close the underlying writer when it's replaced, or when it's explicitly closed through the new Close() function. KnownHostsFile.Add() now also writes the known host to the output if set. I think that makes sense expectation-wise for the type. Turned WriteAll() into WriteTo() to conform with the io.WriterTo interface. Load() is now Open() to better reflect the fact that a file is opened, and kept open. It can now also return errors from the parsing process. The parser does a lot more error checking, and this might be an area where I've changed a desired behaviour as invalid entries no longer are ignored, but aborts the parsing process. That could be changed to a warning, or some kind of parsing feedback. I added KnownHostsFile.TOFU() to fill the developer experience gap that was left after the client no longer knows about KnownHostsFile. It implements a basic non-interactive TOFU flow.
2021-01-13 21:33:48 +00:00
// Add adds a known host to the list of known hosts.
2021-01-14 19:15:08 +00:00
func (k *HostsFile) Add(h Host) error {
tofu: Refactor This commit changes underlying file handling and known hosts parsing. A known hosts file opened through Load() never closed the underlying file. During known hosts parsing most errors were unchecked, or just led to the line being skipped. I removed the KnownHosts type, which didn't really have a role after the refactor. The embedding of KnownHosts in KnownHosts file has been removed as it also leaked the map unprotected by the mutex. The Fingerprint type is now KnownHost and has taken over the responsibility of marshalling and unmarshalling. SetOutput now takes a WriteCloser so that we can close the underlying writer when it's replaced, or when it's explicitly closed through the new Close() function. KnownHostsFile.Add() now also writes the known host to the output if set. I think that makes sense expectation-wise for the type. Turned WriteAll() into WriteTo() to conform with the io.WriterTo interface. Load() is now Open() to better reflect the fact that a file is opened, and kept open. It can now also return errors from the parsing process. The parser does a lot more error checking, and this might be an area where I've changed a desired behaviour as invalid entries no longer are ignored, but aborts the parsing process. That could be changed to a warning, or some kind of parsing feedback. I added KnownHostsFile.TOFU() to fill the developer experience gap that was left after the client no longer knows about KnownHostsFile. It implements a basic non-interactive TOFU flow.
2021-01-13 21:33:48 +00:00
k.mu.Lock()
defer k.mu.Unlock()
if k.hosts == nil {
2021-01-14 19:15:08 +00:00
k.hosts = map[string]Host{}
tofu: Refactor This commit changes underlying file handling and known hosts parsing. A known hosts file opened through Load() never closed the underlying file. During known hosts parsing most errors were unchecked, or just led to the line being skipped. I removed the KnownHosts type, which didn't really have a role after the refactor. The embedding of KnownHosts in KnownHosts file has been removed as it also leaked the map unprotected by the mutex. The Fingerprint type is now KnownHost and has taken over the responsibility of marshalling and unmarshalling. SetOutput now takes a WriteCloser so that we can close the underlying writer when it's replaced, or when it's explicitly closed through the new Close() function. KnownHostsFile.Add() now also writes the known host to the output if set. I think that makes sense expectation-wise for the type. Turned WriteAll() into WriteTo() to conform with the io.WriterTo interface. Load() is now Open() to better reflect the fact that a file is opened, and kept open. It can now also return errors from the parsing process. The parser does a lot more error checking, and this might be an area where I've changed a desired behaviour as invalid entries no longer are ignored, but aborts the parsing process. That could be changed to a warning, or some kind of parsing feedback. I added KnownHostsFile.TOFU() to fill the developer experience gap that was left after the client no longer knows about KnownHostsFile. It implements a basic non-interactive TOFU flow.
2021-01-13 21:33:48 +00:00
}
k.hosts[h.Hostname] = h
2021-01-14 19:15:08 +00:00
if k.writer != nil {
h.WriteTo(k.writer)
k.writer.WriteByte('\n')
tofu: Refactor This commit changes underlying file handling and known hosts parsing. A known hosts file opened through Load() never closed the underlying file. During known hosts parsing most errors were unchecked, or just led to the line being skipped. I removed the KnownHosts type, which didn't really have a role after the refactor. The embedding of KnownHosts in KnownHosts file has been removed as it also leaked the map unprotected by the mutex. The Fingerprint type is now KnownHost and has taken over the responsibility of marshalling and unmarshalling. SetOutput now takes a WriteCloser so that we can close the underlying writer when it's replaced, or when it's explicitly closed through the new Close() function. KnownHostsFile.Add() now also writes the known host to the output if set. I think that makes sense expectation-wise for the type. Turned WriteAll() into WriteTo() to conform with the io.WriterTo interface. Load() is now Open() to better reflect the fact that a file is opened, and kept open. It can now also return errors from the parsing process. The parser does a lot more error checking, and this might be an area where I've changed a desired behaviour as invalid entries no longer are ignored, but aborts the parsing process. That could be changed to a warning, or some kind of parsing feedback. I added KnownHostsFile.TOFU() to fill the developer experience gap that was left after the client no longer knows about KnownHostsFile. It implements a basic non-interactive TOFU flow.
2021-01-13 21:33:48 +00:00
2021-01-14 19:15:08 +00:00
if err := k.writer.Flush(); err != nil {
return fmt.Errorf("failed to write to known host file: %w", err)
}
2020-11-09 17:04:53 +00:00
}
return nil
2020-11-09 17:04:53 +00:00
}
tofu: Refactor This commit changes underlying file handling and known hosts parsing. A known hosts file opened through Load() never closed the underlying file. During known hosts parsing most errors were unchecked, or just led to the line being skipped. I removed the KnownHosts type, which didn't really have a role after the refactor. The embedding of KnownHosts in KnownHosts file has been removed as it also leaked the map unprotected by the mutex. The Fingerprint type is now KnownHost and has taken over the responsibility of marshalling and unmarshalling. SetOutput now takes a WriteCloser so that we can close the underlying writer when it's replaced, or when it's explicitly closed through the new Close() function. KnownHostsFile.Add() now also writes the known host to the output if set. I think that makes sense expectation-wise for the type. Turned WriteAll() into WriteTo() to conform with the io.WriterTo interface. Load() is now Open() to better reflect the fact that a file is opened, and kept open. It can now also return errors from the parsing process. The parser does a lot more error checking, and this might be an area where I've changed a desired behaviour as invalid entries no longer are ignored, but aborts the parsing process. That could be changed to a warning, or some kind of parsing feedback. I added KnownHostsFile.TOFU() to fill the developer experience gap that was left after the client no longer knows about KnownHostsFile. It implements a basic non-interactive TOFU flow.
2021-01-13 21:33:48 +00:00
// Lookup returns the fingerprint of the certificate corresponding to
// the given hostname.
2021-01-14 19:15:08 +00:00
func (k *HostsFile) Lookup(hostname string) (Host, bool) {
tofu: Refactor This commit changes underlying file handling and known hosts parsing. A known hosts file opened through Load() never closed the underlying file. During known hosts parsing most errors were unchecked, or just led to the line being skipped. I removed the KnownHosts type, which didn't really have a role after the refactor. The embedding of KnownHosts in KnownHosts file has been removed as it also leaked the map unprotected by the mutex. The Fingerprint type is now KnownHost and has taken over the responsibility of marshalling and unmarshalling. SetOutput now takes a WriteCloser so that we can close the underlying writer when it's replaced, or when it's explicitly closed through the new Close() function. KnownHostsFile.Add() now also writes the known host to the output if set. I think that makes sense expectation-wise for the type. Turned WriteAll() into WriteTo() to conform with the io.WriterTo interface. Load() is now Open() to better reflect the fact that a file is opened, and kept open. It can now also return errors from the parsing process. The parser does a lot more error checking, and this might be an area where I've changed a desired behaviour as invalid entries no longer are ignored, but aborts the parsing process. That could be changed to a warning, or some kind of parsing feedback. I added KnownHostsFile.TOFU() to fill the developer experience gap that was left after the client no longer knows about KnownHostsFile. It implements a basic non-interactive TOFU flow.
2021-01-13 21:33:48 +00:00
k.mu.RLock()
defer k.mu.RUnlock()
c, ok := k.hosts[hostname]
return c, ok
}
2020-11-09 17:04:53 +00:00
// WriteAll writes all of the known hosts to the provided io.Writer.
2021-01-14 19:15:08 +00:00
func (k *HostsFile) WriteTo(w io.Writer) (int64, error) {
k.mu.RLock()
defer k.mu.RUnlock()
tofu: Refactor This commit changes underlying file handling and known hosts parsing. A known hosts file opened through Load() never closed the underlying file. During known hosts parsing most errors were unchecked, or just led to the line being skipped. I removed the KnownHosts type, which didn't really have a role after the refactor. The embedding of KnownHosts in KnownHosts file has been removed as it also leaked the map unprotected by the mutex. The Fingerprint type is now KnownHost and has taken over the responsibility of marshalling and unmarshalling. SetOutput now takes a WriteCloser so that we can close the underlying writer when it's replaced, or when it's explicitly closed through the new Close() function. KnownHostsFile.Add() now also writes the known host to the output if set. I think that makes sense expectation-wise for the type. Turned WriteAll() into WriteTo() to conform with the io.WriterTo interface. Load() is now Open() to better reflect the fact that a file is opened, and kept open. It can now also return errors from the parsing process. The parser does a lot more error checking, and this might be an area where I've changed a desired behaviour as invalid entries no longer are ignored, but aborts the parsing process. That could be changed to a warning, or some kind of parsing feedback. I added KnownHostsFile.TOFU() to fill the developer experience gap that was left after the client no longer knows about KnownHostsFile. It implements a basic non-interactive TOFU flow.
2021-01-13 21:33:48 +00:00
bw := bufio.NewWriter(w)
var written int64
for _, h := range k.hosts {
n, err := h.WriteTo(bw)
if err != nil {
return written, err
2020-11-09 17:04:53 +00:00
}
tofu: Refactor This commit changes underlying file handling and known hosts parsing. A known hosts file opened through Load() never closed the underlying file. During known hosts parsing most errors were unchecked, or just led to the line being skipped. I removed the KnownHosts type, which didn't really have a role after the refactor. The embedding of KnownHosts in KnownHosts file has been removed as it also leaked the map unprotected by the mutex. The Fingerprint type is now KnownHost and has taken over the responsibility of marshalling and unmarshalling. SetOutput now takes a WriteCloser so that we can close the underlying writer when it's replaced, or when it's explicitly closed through the new Close() function. KnownHostsFile.Add() now also writes the known host to the output if set. I think that makes sense expectation-wise for the type. Turned WriteAll() into WriteTo() to conform with the io.WriterTo interface. Load() is now Open() to better reflect the fact that a file is opened, and kept open. It can now also return errors from the parsing process. The parser does a lot more error checking, and this might be an area where I've changed a desired behaviour as invalid entries no longer are ignored, but aborts the parsing process. That could be changed to a warning, or some kind of parsing feedback. I added KnownHostsFile.TOFU() to fill the developer experience gap that was left after the client no longer knows about KnownHostsFile. It implements a basic non-interactive TOFU flow.
2021-01-13 21:33:48 +00:00
bw.WriteByte('\n')
written += n + 1
2020-11-09 17:04:53 +00:00
}
tofu: Refactor This commit changes underlying file handling and known hosts parsing. A known hosts file opened through Load() never closed the underlying file. During known hosts parsing most errors were unchecked, or just led to the line being skipped. I removed the KnownHosts type, which didn't really have a role after the refactor. The embedding of KnownHosts in KnownHosts file has been removed as it also leaked the map unprotected by the mutex. The Fingerprint type is now KnownHost and has taken over the responsibility of marshalling and unmarshalling. SetOutput now takes a WriteCloser so that we can close the underlying writer when it's replaced, or when it's explicitly closed through the new Close() function. KnownHostsFile.Add() now also writes the known host to the output if set. I think that makes sense expectation-wise for the type. Turned WriteAll() into WriteTo() to conform with the io.WriterTo interface. Load() is now Open() to better reflect the fact that a file is opened, and kept open. It can now also return errors from the parsing process. The parser does a lot more error checking, and this might be an area where I've changed a desired behaviour as invalid entries no longer are ignored, but aborts the parsing process. That could be changed to a warning, or some kind of parsing feedback. I added KnownHostsFile.TOFU() to fill the developer experience gap that was left after the client no longer knows about KnownHostsFile. It implements a basic non-interactive TOFU flow.
2021-01-13 21:33:48 +00:00
return written, bw.Flush()
2020-11-09 17:04:53 +00:00
}
tofu: Refactor This commit changes underlying file handling and known hosts parsing. A known hosts file opened through Load() never closed the underlying file. During known hosts parsing most errors were unchecked, or just led to the line being skipped. I removed the KnownHosts type, which didn't really have a role after the refactor. The embedding of KnownHosts in KnownHosts file has been removed as it also leaked the map unprotected by the mutex. The Fingerprint type is now KnownHost and has taken over the responsibility of marshalling and unmarshalling. SetOutput now takes a WriteCloser so that we can close the underlying writer when it's replaced, or when it's explicitly closed through the new Close() function. KnownHostsFile.Add() now also writes the known host to the output if set. I think that makes sense expectation-wise for the type. Turned WriteAll() into WriteTo() to conform with the io.WriterTo interface. Load() is now Open() to better reflect the fact that a file is opened, and kept open. It can now also return errors from the parsing process. The parser does a lot more error checking, and this might be an area where I've changed a desired behaviour as invalid entries no longer are ignored, but aborts the parsing process. That could be changed to a warning, or some kind of parsing feedback. I added KnownHostsFile.TOFU() to fill the developer experience gap that was left after the client no longer knows about KnownHostsFile. It implements a basic non-interactive TOFU flow.
2021-01-13 21:33:48 +00:00
// Open loads the known hosts from the provided path.
2020-11-09 18:57:30 +00:00
// It creates the file if it does not exist.
// New known hosts will be appended to the file.
2021-01-14 19:15:08 +00:00
func (k *HostsFile) Open(path string) error {
f, err := os.OpenFile(path, os.O_CREATE|os.O_RDWR, 0644)
2020-09-26 03:06:54 +00:00
if err != nil {
return err
2020-09-26 03:06:54 +00:00
}
tofu: Refactor This commit changes underlying file handling and known hosts parsing. A known hosts file opened through Load() never closed the underlying file. During known hosts parsing most errors were unchecked, or just led to the line being skipped. I removed the KnownHosts type, which didn't really have a role after the refactor. The embedding of KnownHosts in KnownHosts file has been removed as it also leaked the map unprotected by the mutex. The Fingerprint type is now KnownHost and has taken over the responsibility of marshalling and unmarshalling. SetOutput now takes a WriteCloser so that we can close the underlying writer when it's replaced, or when it's explicitly closed through the new Close() function. KnownHostsFile.Add() now also writes the known host to the output if set. I think that makes sense expectation-wise for the type. Turned WriteAll() into WriteTo() to conform with the io.WriterTo interface. Load() is now Open() to better reflect the fact that a file is opened, and kept open. It can now also return errors from the parsing process. The parser does a lot more error checking, and this might be an area where I've changed a desired behaviour as invalid entries no longer are ignored, but aborts the parsing process. That could be changed to a warning, or some kind of parsing feedback. I added KnownHostsFile.TOFU() to fill the developer experience gap that was left after the client no longer knows about KnownHostsFile. It implements a basic non-interactive TOFU flow.
2021-01-13 21:33:48 +00:00
err = k.Parse(f)
if err != nil {
_ = f.Close()
return err
}
err = k.SetOutput(f)
if err != nil {
_ = f.Close()
return err
}
return nil
2020-09-26 03:06:54 +00:00
}
// Parse parses the provided reader and adds the parsed known hosts to the list.
2020-11-09 17:26:08 +00:00
// Invalid entries are ignored.
2021-01-14 19:15:08 +00:00
func (k *HostsFile) Parse(r io.Reader) error {
k.mu.Lock()
defer k.mu.Unlock()
tofu: Refactor This commit changes underlying file handling and known hosts parsing. A known hosts file opened through Load() never closed the underlying file. During known hosts parsing most errors were unchecked, or just led to the line being skipped. I removed the KnownHosts type, which didn't really have a role after the refactor. The embedding of KnownHosts in KnownHosts file has been removed as it also leaked the map unprotected by the mutex. The Fingerprint type is now KnownHost and has taken over the responsibility of marshalling and unmarshalling. SetOutput now takes a WriteCloser so that we can close the underlying writer when it's replaced, or when it's explicitly closed through the new Close() function. KnownHostsFile.Add() now also writes the known host to the output if set. I think that makes sense expectation-wise for the type. Turned WriteAll() into WriteTo() to conform with the io.WriterTo interface. Load() is now Open() to better reflect the fact that a file is opened, and kept open. It can now also return errors from the parsing process. The parser does a lot more error checking, and this might be an area where I've changed a desired behaviour as invalid entries no longer are ignored, but aborts the parsing process. That could be changed to a warning, or some kind of parsing feedback. I added KnownHostsFile.TOFU() to fill the developer experience gap that was left after the client no longer knows about KnownHostsFile. It implements a basic non-interactive TOFU flow.
2021-01-13 21:33:48 +00:00
if k.hosts == nil {
2021-01-14 19:15:08 +00:00
k.hosts = map[string]Host{}
}
tofu: Refactor This commit changes underlying file handling and known hosts parsing. A known hosts file opened through Load() never closed the underlying file. During known hosts parsing most errors were unchecked, or just led to the line being skipped. I removed the KnownHosts type, which didn't really have a role after the refactor. The embedding of KnownHosts in KnownHosts file has been removed as it also leaked the map unprotected by the mutex. The Fingerprint type is now KnownHost and has taken over the responsibility of marshalling and unmarshalling. SetOutput now takes a WriteCloser so that we can close the underlying writer when it's replaced, or when it's explicitly closed through the new Close() function. KnownHostsFile.Add() now also writes the known host to the output if set. I think that makes sense expectation-wise for the type. Turned WriteAll() into WriteTo() to conform with the io.WriterTo interface. Load() is now Open() to better reflect the fact that a file is opened, and kept open. It can now also return errors from the parsing process. The parser does a lot more error checking, and this might be an area where I've changed a desired behaviour as invalid entries no longer are ignored, but aborts the parsing process. That could be changed to a warning, or some kind of parsing feedback. I added KnownHostsFile.TOFU() to fill the developer experience gap that was left after the client no longer knows about KnownHostsFile. It implements a basic non-interactive TOFU flow.
2021-01-13 21:33:48 +00:00
2020-09-25 22:53:20 +00:00
scanner := bufio.NewScanner(r)
tofu: Refactor This commit changes underlying file handling and known hosts parsing. A known hosts file opened through Load() never closed the underlying file. During known hosts parsing most errors were unchecked, or just led to the line being skipped. I removed the KnownHosts type, which didn't really have a role after the refactor. The embedding of KnownHosts in KnownHosts file has been removed as it also leaked the map unprotected by the mutex. The Fingerprint type is now KnownHost and has taken over the responsibility of marshalling and unmarshalling. SetOutput now takes a WriteCloser so that we can close the underlying writer when it's replaced, or when it's explicitly closed through the new Close() function. KnownHostsFile.Add() now also writes the known host to the output if set. I think that makes sense expectation-wise for the type. Turned WriteAll() into WriteTo() to conform with the io.WriterTo interface. Load() is now Open() to better reflect the fact that a file is opened, and kept open. It can now also return errors from the parsing process. The parser does a lot more error checking, and this might be an area where I've changed a desired behaviour as invalid entries no longer are ignored, but aborts the parsing process. That could be changed to a warning, or some kind of parsing feedback. I added KnownHostsFile.TOFU() to fill the developer experience gap that was left after the client no longer knows about KnownHostsFile. It implements a basic non-interactive TOFU flow.
2021-01-13 21:33:48 +00:00
var line int
2020-09-25 22:53:20 +00:00
for scanner.Scan() {
tofu: Refactor This commit changes underlying file handling and known hosts parsing. A known hosts file opened through Load() never closed the underlying file. During known hosts parsing most errors were unchecked, or just led to the line being skipped. I removed the KnownHosts type, which didn't really have a role after the refactor. The embedding of KnownHosts in KnownHosts file has been removed as it also leaked the map unprotected by the mutex. The Fingerprint type is now KnownHost and has taken over the responsibility of marshalling and unmarshalling. SetOutput now takes a WriteCloser so that we can close the underlying writer when it's replaced, or when it's explicitly closed through the new Close() function. KnownHostsFile.Add() now also writes the known host to the output if set. I think that makes sense expectation-wise for the type. Turned WriteAll() into WriteTo() to conform with the io.WriterTo interface. Load() is now Open() to better reflect the fact that a file is opened, and kept open. It can now also return errors from the parsing process. The parser does a lot more error checking, and this might be an area where I've changed a desired behaviour as invalid entries no longer are ignored, but aborts the parsing process. That could be changed to a warning, or some kind of parsing feedback. I added KnownHostsFile.TOFU() to fill the developer experience gap that was left after the client no longer knows about KnownHostsFile. It implements a basic non-interactive TOFU flow.
2021-01-13 21:33:48 +00:00
line++
2020-09-25 22:53:20 +00:00
tofu: Refactor This commit changes underlying file handling and known hosts parsing. A known hosts file opened through Load() never closed the underlying file. During known hosts parsing most errors were unchecked, or just led to the line being skipped. I removed the KnownHosts type, which didn't really have a role after the refactor. The embedding of KnownHosts in KnownHosts file has been removed as it also leaked the map unprotected by the mutex. The Fingerprint type is now KnownHost and has taken over the responsibility of marshalling and unmarshalling. SetOutput now takes a WriteCloser so that we can close the underlying writer when it's replaced, or when it's explicitly closed through the new Close() function. KnownHostsFile.Add() now also writes the known host to the output if set. I think that makes sense expectation-wise for the type. Turned WriteAll() into WriteTo() to conform with the io.WriterTo interface. Load() is now Open() to better reflect the fact that a file is opened, and kept open. It can now also return errors from the parsing process. The parser does a lot more error checking, and this might be an area where I've changed a desired behaviour as invalid entries no longer are ignored, but aborts the parsing process. That could be changed to a warning, or some kind of parsing feedback. I added KnownHostsFile.TOFU() to fill the developer experience gap that was left after the client no longer knows about KnownHostsFile. It implements a basic non-interactive TOFU flow.
2021-01-13 21:33:48 +00:00
text := scanner.Bytes()
if len(text) == 0 {
continue
}
2020-09-25 22:53:20 +00:00
2021-01-14 19:15:08 +00:00
var h Host
tofu: Refactor This commit changes underlying file handling and known hosts parsing. A known hosts file opened through Load() never closed the underlying file. During known hosts parsing most errors were unchecked, or just led to the line being skipped. I removed the KnownHosts type, which didn't really have a role after the refactor. The embedding of KnownHosts in KnownHosts file has been removed as it also leaked the map unprotected by the mutex. The Fingerprint type is now KnownHost and has taken over the responsibility of marshalling and unmarshalling. SetOutput now takes a WriteCloser so that we can close the underlying writer when it's replaced, or when it's explicitly closed through the new Close() function. KnownHostsFile.Add() now also writes the known host to the output if set. I think that makes sense expectation-wise for the type. Turned WriteAll() into WriteTo() to conform with the io.WriterTo interface. Load() is now Open() to better reflect the fact that a file is opened, and kept open. It can now also return errors from the parsing process. The parser does a lot more error checking, and this might be an area where I've changed a desired behaviour as invalid entries no longer are ignored, but aborts the parsing process. That could be changed to a warning, or some kind of parsing feedback. I added KnownHostsFile.TOFU() to fill the developer experience gap that was left after the client no longer knows about KnownHostsFile. It implements a basic non-interactive TOFU flow.
2021-01-13 21:33:48 +00:00
err := h.UnmarshalText(text)
2020-11-06 03:30:13 +00:00
if err != nil {
tofu: Refactor This commit changes underlying file handling and known hosts parsing. A known hosts file opened through Load() never closed the underlying file. During known hosts parsing most errors were unchecked, or just led to the line being skipped. I removed the KnownHosts type, which didn't really have a role after the refactor. The embedding of KnownHosts in KnownHosts file has been removed as it also leaked the map unprotected by the mutex. The Fingerprint type is now KnownHost and has taken over the responsibility of marshalling and unmarshalling. SetOutput now takes a WriteCloser so that we can close the underlying writer when it's replaced, or when it's explicitly closed through the new Close() function. KnownHostsFile.Add() now also writes the known host to the output if set. I think that makes sense expectation-wise for the type. Turned WriteAll() into WriteTo() to conform with the io.WriterTo interface. Load() is now Open() to better reflect the fact that a file is opened, and kept open. It can now also return errors from the parsing process. The parser does a lot more error checking, and this might be an area where I've changed a desired behaviour as invalid entries no longer are ignored, but aborts the parsing process. That could be changed to a warning, or some kind of parsing feedback. I added KnownHostsFile.TOFU() to fill the developer experience gap that was left after the client no longer knows about KnownHostsFile. It implements a basic non-interactive TOFU flow.
2021-01-13 21:33:48 +00:00
return fmt.Errorf("error when parsing line %d: %w",
line, err)
2020-11-06 03:30:13 +00:00
}
tofu: Refactor This commit changes underlying file handling and known hosts parsing. A known hosts file opened through Load() never closed the underlying file. During known hosts parsing most errors were unchecked, or just led to the line being skipped. I removed the KnownHosts type, which didn't really have a role after the refactor. The embedding of KnownHosts in KnownHosts file has been removed as it also leaked the map unprotected by the mutex. The Fingerprint type is now KnownHost and has taken over the responsibility of marshalling and unmarshalling. SetOutput now takes a WriteCloser so that we can close the underlying writer when it's replaced, or when it's explicitly closed through the new Close() function. KnownHostsFile.Add() now also writes the known host to the output if set. I think that makes sense expectation-wise for the type. Turned WriteAll() into WriteTo() to conform with the io.WriterTo interface. Load() is now Open() to better reflect the fact that a file is opened, and kept open. It can now also return errors from the parsing process. The parser does a lot more error checking, and this might be an area where I've changed a desired behaviour as invalid entries no longer are ignored, but aborts the parsing process. That could be changed to a warning, or some kind of parsing feedback. I added KnownHostsFile.TOFU() to fill the developer experience gap that was left after the client no longer knows about KnownHostsFile. It implements a basic non-interactive TOFU flow.
2021-01-13 21:33:48 +00:00
k.hosts[h.Hostname] = h
}
err := scanner.Err()
if err != nil {
return fmt.Errorf("failed to read lines: %w", err)
2020-09-25 22:53:20 +00:00
}
tofu: Refactor This commit changes underlying file handling and known hosts parsing. A known hosts file opened through Load() never closed the underlying file. During known hosts parsing most errors were unchecked, or just led to the line being skipped. I removed the KnownHosts type, which didn't really have a role after the refactor. The embedding of KnownHosts in KnownHosts file has been removed as it also leaked the map unprotected by the mutex. The Fingerprint type is now KnownHost and has taken over the responsibility of marshalling and unmarshalling. SetOutput now takes a WriteCloser so that we can close the underlying writer when it's replaced, or when it's explicitly closed through the new Close() function. KnownHostsFile.Add() now also writes the known host to the output if set. I think that makes sense expectation-wise for the type. Turned WriteAll() into WriteTo() to conform with the io.WriterTo interface. Load() is now Open() to better reflect the fact that a file is opened, and kept open. It can now also return errors from the parsing process. The parser does a lot more error checking, and this might be an area where I've changed a desired behaviour as invalid entries no longer are ignored, but aborts the parsing process. That could be changed to a warning, or some kind of parsing feedback. I added KnownHostsFile.TOFU() to fill the developer experience gap that was left after the client no longer knows about KnownHostsFile. It implements a basic non-interactive TOFU flow.
2021-01-13 21:33:48 +00:00
return nil
2020-09-26 00:55:37 +00:00
}
2020-09-25 22:53:20 +00:00
2021-01-14 19:15:08 +00:00
func (k *HostsFile) TOFU(hostname string, cert *x509.Certificate) error {
host := NewHost(hostname, cert.Raw, cert.NotAfter)
tofu: Refactor This commit changes underlying file handling and known hosts parsing. A known hosts file opened through Load() never closed the underlying file. During known hosts parsing most errors were unchecked, or just led to the line being skipped. I removed the KnownHosts type, which didn't really have a role after the refactor. The embedding of KnownHosts in KnownHosts file has been removed as it also leaked the map unprotected by the mutex. The Fingerprint type is now KnownHost and has taken over the responsibility of marshalling and unmarshalling. SetOutput now takes a WriteCloser so that we can close the underlying writer when it's replaced, or when it's explicitly closed through the new Close() function. KnownHostsFile.Add() now also writes the known host to the output if set. I think that makes sense expectation-wise for the type. Turned WriteAll() into WriteTo() to conform with the io.WriterTo interface. Load() is now Open() to better reflect the fact that a file is opened, and kept open. It can now also return errors from the parsing process. The parser does a lot more error checking, and this might be an area where I've changed a desired behaviour as invalid entries no longer are ignored, but aborts the parsing process. That could be changed to a warning, or some kind of parsing feedback. I added KnownHostsFile.TOFU() to fill the developer experience gap that was left after the client no longer knows about KnownHostsFile. It implements a basic non-interactive TOFU flow.
2021-01-13 21:33:48 +00:00
knownHost, ok := k.Lookup(hostname)
if !ok || time.Now().After(knownHost.Expires) {
k.Add(host)
return nil
}
// Check fingerprint
if !bytes.Equal(knownHost.Fingerprint, host.Fingerprint) {
return fmt.Errorf("fingerprint for %q does not match", hostname)
}
return nil
}
tofu: Refactor This commit changes underlying file handling and known hosts parsing. A known hosts file opened through Load() never closed the underlying file. During known hosts parsing most errors were unchecked, or just led to the line being skipped. I removed the KnownHosts type, which didn't really have a role after the refactor. The embedding of KnownHosts in KnownHosts file has been removed as it also leaked the map unprotected by the mutex. The Fingerprint type is now KnownHost and has taken over the responsibility of marshalling and unmarshalling. SetOutput now takes a WriteCloser so that we can close the underlying writer when it's replaced, or when it's explicitly closed through the new Close() function. KnownHostsFile.Add() now also writes the known host to the output if set. I think that makes sense expectation-wise for the type. Turned WriteAll() into WriteTo() to conform with the io.WriterTo interface. Load() is now Open() to better reflect the fact that a file is opened, and kept open. It can now also return errors from the parsing process. The parser does a lot more error checking, and this might be an area where I've changed a desired behaviour as invalid entries no longer are ignored, but aborts the parsing process. That could be changed to a warning, or some kind of parsing feedback. I added KnownHostsFile.TOFU() to fill the developer experience gap that was left after the client no longer knows about KnownHostsFile. It implements a basic non-interactive TOFU flow.
2021-01-13 21:33:48 +00:00
type Fingerprint []byte
func (f Fingerprint) String() string {
var sb strings.Builder
for i, b := range f {
if i > 0 {
tofu: Refactor This commit changes underlying file handling and known hosts parsing. A known hosts file opened through Load() never closed the underlying file. During known hosts parsing most errors were unchecked, or just led to the line being skipped. I removed the KnownHosts type, which didn't really have a role after the refactor. The embedding of KnownHosts in KnownHosts file has been removed as it also leaked the map unprotected by the mutex. The Fingerprint type is now KnownHost and has taken over the responsibility of marshalling and unmarshalling. SetOutput now takes a WriteCloser so that we can close the underlying writer when it's replaced, or when it's explicitly closed through the new Close() function. KnownHostsFile.Add() now also writes the known host to the output if set. I think that makes sense expectation-wise for the type. Turned WriteAll() into WriteTo() to conform with the io.WriterTo interface. Load() is now Open() to better reflect the fact that a file is opened, and kept open. It can now also return errors from the parsing process. The parser does a lot more error checking, and this might be an area where I've changed a desired behaviour as invalid entries no longer are ignored, but aborts the parsing process. That could be changed to a warning, or some kind of parsing feedback. I added KnownHostsFile.TOFU() to fill the developer experience gap that was left after the client no longer knows about KnownHostsFile. It implements a basic non-interactive TOFU flow.
2021-01-13 21:33:48 +00:00
sb.WriteByte(':')
}
tofu: Refactor This commit changes underlying file handling and known hosts parsing. A known hosts file opened through Load() never closed the underlying file. During known hosts parsing most errors were unchecked, or just led to the line being skipped. I removed the KnownHosts type, which didn't really have a role after the refactor. The embedding of KnownHosts in KnownHosts file has been removed as it also leaked the map unprotected by the mutex. The Fingerprint type is now KnownHost and has taken over the responsibility of marshalling and unmarshalling. SetOutput now takes a WriteCloser so that we can close the underlying writer when it's replaced, or when it's explicitly closed through the new Close() function. KnownHostsFile.Add() now also writes the known host to the output if set. I think that makes sense expectation-wise for the type. Turned WriteAll() into WriteTo() to conform with the io.WriterTo interface. Load() is now Open() to better reflect the fact that a file is opened, and kept open. It can now also return errors from the parsing process. The parser does a lot more error checking, and this might be an area where I've changed a desired behaviour as invalid entries no longer are ignored, but aborts the parsing process. That could be changed to a warning, or some kind of parsing feedback. I added KnownHostsFile.TOFU() to fill the developer experience gap that was left after the client no longer knows about KnownHostsFile. It implements a basic non-interactive TOFU flow.
2021-01-13 21:33:48 +00:00
fmt.Fprintf(&sb, "%02X", b)
}
tofu: Refactor This commit changes underlying file handling and known hosts parsing. A known hosts file opened through Load() never closed the underlying file. During known hosts parsing most errors were unchecked, or just led to the line being skipped. I removed the KnownHosts type, which didn't really have a role after the refactor. The embedding of KnownHosts in KnownHosts file has been removed as it also leaked the map unprotected by the mutex. The Fingerprint type is now KnownHost and has taken over the responsibility of marshalling and unmarshalling. SetOutput now takes a WriteCloser so that we can close the underlying writer when it's replaced, or when it's explicitly closed through the new Close() function. KnownHostsFile.Add() now also writes the known host to the output if set. I think that makes sense expectation-wise for the type. Turned WriteAll() into WriteTo() to conform with the io.WriterTo interface. Load() is now Open() to better reflect the fact that a file is opened, and kept open. It can now also return errors from the parsing process. The parser does a lot more error checking, and this might be an area where I've changed a desired behaviour as invalid entries no longer are ignored, but aborts the parsing process. That could be changed to a warning, or some kind of parsing feedback. I added KnownHostsFile.TOFU() to fill the developer experience gap that was left after the client no longer knows about KnownHostsFile. It implements a basic non-interactive TOFU flow.
2021-01-13 21:33:48 +00:00
return sb.String()
}
2021-01-14 19:15:08 +00:00
// Host represents a known host entry for a fingerprint using a certain algorithm.
type Host struct {
tofu: Refactor This commit changes underlying file handling and known hosts parsing. A known hosts file opened through Load() never closed the underlying file. During known hosts parsing most errors were unchecked, or just led to the line being skipped. I removed the KnownHosts type, which didn't really have a role after the refactor. The embedding of KnownHosts in KnownHosts file has been removed as it also leaked the map unprotected by the mutex. The Fingerprint type is now KnownHost and has taken over the responsibility of marshalling and unmarshalling. SetOutput now takes a WriteCloser so that we can close the underlying writer when it's replaced, or when it's explicitly closed through the new Close() function. KnownHostsFile.Add() now also writes the known host to the output if set. I think that makes sense expectation-wise for the type. Turned WriteAll() into WriteTo() to conform with the io.WriterTo interface. Load() is now Open() to better reflect the fact that a file is opened, and kept open. It can now also return errors from the parsing process. The parser does a lot more error checking, and this might be an area where I've changed a desired behaviour as invalid entries no longer are ignored, but aborts the parsing process. That could be changed to a warning, or some kind of parsing feedback. I added KnownHostsFile.TOFU() to fill the developer experience gap that was left after the client no longer knows about KnownHostsFile. It implements a basic non-interactive TOFU flow.
2021-01-13 21:33:48 +00:00
Hostname string // hostname
Algorithm string // fingerprint algorithm e.g. SHA-512
Fingerprint Fingerprint // fingerprint
Expires time.Time // unix time of the fingerprint expiration date
}
2021-01-14 19:15:08 +00:00
// NewHost returns the known host entry with a SHA-512
// fingerprint of the provided raw data.
func NewHost(hostname string, raw []byte, expires time.Time) Host {
sum := sha512.Sum512(raw)
return Host{
Hostname: hostname,
Algorithm: "SHA-512",
Fingerprint: sum[:],
Expires: expires,
}
}
func (h *Host) UnmarshalText(text []byte) error {
tofu: Refactor This commit changes underlying file handling and known hosts parsing. A known hosts file opened through Load() never closed the underlying file. During known hosts parsing most errors were unchecked, or just led to the line being skipped. I removed the KnownHosts type, which didn't really have a role after the refactor. The embedding of KnownHosts in KnownHosts file has been removed as it also leaked the map unprotected by the mutex. The Fingerprint type is now KnownHost and has taken over the responsibility of marshalling and unmarshalling. SetOutput now takes a WriteCloser so that we can close the underlying writer when it's replaced, or when it's explicitly closed through the new Close() function. KnownHostsFile.Add() now also writes the known host to the output if set. I think that makes sense expectation-wise for the type. Turned WriteAll() into WriteTo() to conform with the io.WriterTo interface. Load() is now Open() to better reflect the fact that a file is opened, and kept open. It can now also return errors from the parsing process. The parser does a lot more error checking, and this might be an area where I've changed a desired behaviour as invalid entries no longer are ignored, but aborts the parsing process. That could be changed to a warning, or some kind of parsing feedback. I added KnownHostsFile.TOFU() to fill the developer experience gap that was left after the client no longer knows about KnownHostsFile. It implements a basic non-interactive TOFU flow.
2021-01-13 21:33:48 +00:00
const format = "hostname algorithm hex-fingerprint expiry-unix-ts"
parts := bytes.Split(text, []byte(" "))
if len(parts) != 4 {
return fmt.Errorf(
"expected the format %q", format)
}
if len(parts[0]) == 0 {
return errors.New("empty hostname")
}
2021-01-14 19:15:08 +00:00
h.Hostname = string(parts[0])
tofu: Refactor This commit changes underlying file handling and known hosts parsing. A known hosts file opened through Load() never closed the underlying file. During known hosts parsing most errors were unchecked, or just led to the line being skipped. I removed the KnownHosts type, which didn't really have a role after the refactor. The embedding of KnownHosts in KnownHosts file has been removed as it also leaked the map unprotected by the mutex. The Fingerprint type is now KnownHost and has taken over the responsibility of marshalling and unmarshalling. SetOutput now takes a WriteCloser so that we can close the underlying writer when it's replaced, or when it's explicitly closed through the new Close() function. KnownHostsFile.Add() now also writes the known host to the output if set. I think that makes sense expectation-wise for the type. Turned WriteAll() into WriteTo() to conform with the io.WriterTo interface. Load() is now Open() to better reflect the fact that a file is opened, and kept open. It can now also return errors from the parsing process. The parser does a lot more error checking, and this might be an area where I've changed a desired behaviour as invalid entries no longer are ignored, but aborts the parsing process. That could be changed to a warning, or some kind of parsing feedback. I added KnownHostsFile.TOFU() to fill the developer experience gap that was left after the client no longer knows about KnownHostsFile. It implements a basic non-interactive TOFU flow.
2021-01-13 21:33:48 +00:00
algorithm := string(parts[1])
if algorithm != "SHA-512" {
return fmt.Errorf(
"unsupported algorithm %q", algorithm)
}
2021-01-14 19:15:08 +00:00
h.Algorithm = algorithm
tofu: Refactor This commit changes underlying file handling and known hosts parsing. A known hosts file opened through Load() never closed the underlying file. During known hosts parsing most errors were unchecked, or just led to the line being skipped. I removed the KnownHosts type, which didn't really have a role after the refactor. The embedding of KnownHosts in KnownHosts file has been removed as it also leaked the map unprotected by the mutex. The Fingerprint type is now KnownHost and has taken over the responsibility of marshalling and unmarshalling. SetOutput now takes a WriteCloser so that we can close the underlying writer when it's replaced, or when it's explicitly closed through the new Close() function. KnownHostsFile.Add() now also writes the known host to the output if set. I think that makes sense expectation-wise for the type. Turned WriteAll() into WriteTo() to conform with the io.WriterTo interface. Load() is now Open() to better reflect the fact that a file is opened, and kept open. It can now also return errors from the parsing process. The parser does a lot more error checking, and this might be an area where I've changed a desired behaviour as invalid entries no longer are ignored, but aborts the parsing process. That could be changed to a warning, or some kind of parsing feedback. I added KnownHostsFile.TOFU() to fill the developer experience gap that was left after the client no longer knows about KnownHostsFile. It implements a basic non-interactive TOFU flow.
2021-01-13 21:33:48 +00:00
fingerprint := make([]byte, 0, sha512.Size)
scan := bufio.NewScanner(bytes.NewReader(parts[2]))
scan.Split(scanFingerprint)
for scan.Scan() {
b, err := strconv.ParseUint(scan.Text(), 16, 8)
if err != nil {
return fmt.Errorf("failed to parse fingerprint hash: %w", err)
}
fingerprint = append(fingerprint, byte(b))
}
if len(fingerprint) != sha512.Size {
return fmt.Errorf("invalid fingerprint size %d, expected %d",
len(fingerprint), sha512.Size)
}
2021-01-14 19:15:08 +00:00
h.Fingerprint = fingerprint
tofu: Refactor This commit changes underlying file handling and known hosts parsing. A known hosts file opened through Load() never closed the underlying file. During known hosts parsing most errors were unchecked, or just led to the line being skipped. I removed the KnownHosts type, which didn't really have a role after the refactor. The embedding of KnownHosts in KnownHosts file has been removed as it also leaked the map unprotected by the mutex. The Fingerprint type is now KnownHost and has taken over the responsibility of marshalling and unmarshalling. SetOutput now takes a WriteCloser so that we can close the underlying writer when it's replaced, or when it's explicitly closed through the new Close() function. KnownHostsFile.Add() now also writes the known host to the output if set. I think that makes sense expectation-wise for the type. Turned WriteAll() into WriteTo() to conform with the io.WriterTo interface. Load() is now Open() to better reflect the fact that a file is opened, and kept open. It can now also return errors from the parsing process. The parser does a lot more error checking, and this might be an area where I've changed a desired behaviour as invalid entries no longer are ignored, but aborts the parsing process. That could be changed to a warning, or some kind of parsing feedback. I added KnownHostsFile.TOFU() to fill the developer experience gap that was left after the client no longer knows about KnownHostsFile. It implements a basic non-interactive TOFU flow.
2021-01-13 21:33:48 +00:00
unix, err := strconv.ParseInt(string(parts[3]), 10, 0)
if err != nil {
return fmt.Errorf(
"invalid unix timestamp: %w", err)
}
2021-01-14 19:15:08 +00:00
h.Expires = time.Unix(unix, 0)
tofu: Refactor This commit changes underlying file handling and known hosts parsing. A known hosts file opened through Load() never closed the underlying file. During known hosts parsing most errors were unchecked, or just led to the line being skipped. I removed the KnownHosts type, which didn't really have a role after the refactor. The embedding of KnownHosts in KnownHosts file has been removed as it also leaked the map unprotected by the mutex. The Fingerprint type is now KnownHost and has taken over the responsibility of marshalling and unmarshalling. SetOutput now takes a WriteCloser so that we can close the underlying writer when it's replaced, or when it's explicitly closed through the new Close() function. KnownHostsFile.Add() now also writes the known host to the output if set. I think that makes sense expectation-wise for the type. Turned WriteAll() into WriteTo() to conform with the io.WriterTo interface. Load() is now Open() to better reflect the fact that a file is opened, and kept open. It can now also return errors from the parsing process. The parser does a lot more error checking, and this might be an area where I've changed a desired behaviour as invalid entries no longer are ignored, but aborts the parsing process. That could be changed to a warning, or some kind of parsing feedback. I added KnownHostsFile.TOFU() to fill the developer experience gap that was left after the client no longer knows about KnownHostsFile. It implements a basic non-interactive TOFU flow.
2021-01-13 21:33:48 +00:00
return nil
}
2021-01-14 19:15:08 +00:00
func (h *Host) WriteTo(w io.Writer) (int64, error) {
tofu: Refactor This commit changes underlying file handling and known hosts parsing. A known hosts file opened through Load() never closed the underlying file. During known hosts parsing most errors were unchecked, or just led to the line being skipped. I removed the KnownHosts type, which didn't really have a role after the refactor. The embedding of KnownHosts in KnownHosts file has been removed as it also leaked the map unprotected by the mutex. The Fingerprint type is now KnownHost and has taken over the responsibility of marshalling and unmarshalling. SetOutput now takes a WriteCloser so that we can close the underlying writer when it's replaced, or when it's explicitly closed through the new Close() function. KnownHostsFile.Add() now also writes the known host to the output if set. I think that makes sense expectation-wise for the type. Turned WriteAll() into WriteTo() to conform with the io.WriterTo interface. Load() is now Open() to better reflect the fact that a file is opened, and kept open. It can now also return errors from the parsing process. The parser does a lot more error checking, and this might be an area where I've changed a desired behaviour as invalid entries no longer are ignored, but aborts the parsing process. That could be changed to a warning, or some kind of parsing feedback. I added KnownHostsFile.TOFU() to fill the developer experience gap that was left after the client no longer knows about KnownHostsFile. It implements a basic non-interactive TOFU flow.
2021-01-13 21:33:48 +00:00
bw := bufio.NewWriter(w)
var written, n int
n, _ = bw.WriteString(h.Hostname)
bw.WriteByte(' ')
written += n + 1
n, _ = bw.WriteString(h.Algorithm)
bw.WriteByte(' ')
written += n + 1
n, _ = bw.WriteString(h.Fingerprint.String())
bw.WriteByte(' ')
written += n + 1
n, _ = bw.WriteString(strconv.FormatInt(h.Expires.Unix(), 10))
written += n
return int64(written), bw.Flush()
}
func scanFingerprint(data []byte, atEOF bool) (advance int, token []byte, err error) {
if atEOF && len(data) == 0 {
return 0, nil, nil
}
if i := bytes.IndexByte(data, ':'); i >= 0 {
// We have a full newline-terminated line.
return i + 1, data[0:i], nil
}
// If we're at EOF, we have a final, non-terminated hex byte
if atEOF {
return len(data), data, nil
}
// Request more data.
return 0, nil, nil
}