-
Notifications
You must be signed in to change notification settings - Fork 154
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Sergey Mezentsev
committed
May 9, 2024
1 parent
ce8b5a5
commit 8dba74e
Showing
20 changed files
with
387 additions
and
43 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,141 @@ | ||
package shim | ||
|
||
import ( | ||
"bufio" | ||
"fmt" | ||
"io" | ||
"os" | ||
"slices" | ||
|
||
"github.com/ztrue/tracerr" | ||
"golang.org/x/crypto/ssh" | ||
) | ||
|
||
func PublicKeyFingerprint(key string) (string, error) { | ||
pk, _, _, _, err := ssh.ParseAuthorizedKey([]byte(key)) | ||
if err != nil { | ||
return "", tracerr.Wrap(err) | ||
} | ||
keyFingerprint := ssh.FingerprintSHA256(pk) | ||
return keyFingerprint, nil | ||
} | ||
|
||
func IsPublicKeysEqual(left string, right string) bool { | ||
leftFingerprint, err := PublicKeyFingerprint(left) | ||
if err != nil { | ||
return false | ||
} | ||
|
||
rightFingerprint, err := PublicKeyFingerprint(right) | ||
if err != nil { | ||
return false | ||
} | ||
|
||
return leftFingerprint == rightFingerprint | ||
} | ||
|
||
func RemovePublicKeys(fileKeys []string, keysToRemove []string) []string { | ||
newKeys := slices.DeleteFunc(fileKeys, func(fileKey string) bool { | ||
delete := slices.ContainsFunc(keysToRemove, func(removeKey string) bool { | ||
return IsPublicKeysEqual(fileKey, removeKey) | ||
}) | ||
return delete | ||
}) | ||
return newKeys | ||
} | ||
|
||
func AppendPublicKeys(fileKeys []string, keysToAppend []string) []string { | ||
newKeys := []string{} | ||
newKeys = append(newKeys, fileKeys...) | ||
newKeys = append(newKeys, keysToAppend...) | ||
return newKeys | ||
} | ||
|
||
type AuthorizedKeys struct { | ||
user string | ||
rootPath string | ||
} | ||
|
||
func (ak AuthorizedKeys) AppendPublicKeys(publicKeys []string) error { | ||
return ak.transformAuthorizedKeys(AppendPublicKeys, publicKeys) | ||
} | ||
|
||
func (ak AuthorizedKeys) RemovePublicKeys(publicKeys []string) error { | ||
return ak.transformAuthorizedKeys(RemovePublicKeys, publicKeys) | ||
} | ||
|
||
func (ak AuthorizedKeys) read(r io.Reader) ([]string, error) { | ||
lines := []string{} | ||
scanner := bufio.NewScanner(r) | ||
for scanner.Scan() { | ||
text := scanner.Text() | ||
lines = append(lines, text) | ||
} | ||
if err := scanner.Err(); err != nil { | ||
return []string{}, tracerr.Wrap(err) | ||
} | ||
return lines, nil | ||
} | ||
|
||
func (ak AuthorizedKeys) write(w io.Writer, lines []string) error { | ||
wr := bufio.NewWriter(w) | ||
for _, line := range lines { | ||
_, err := fmt.Fprintln(wr, line) | ||
if err != nil { | ||
return tracerr.Wrap(err) | ||
|
||
} | ||
} | ||
return wr.Flush() | ||
} | ||
|
||
func (ak AuthorizedKeys) GetAuthorizedKeysPath() string { | ||
return fmt.Sprintf("%s/home/%s/.ssh/authorized_keys", ak.rootPath, ak.user) | ||
} | ||
|
||
func (ak AuthorizedKeys) transformAuthorizedKeys(transform func([]string, []string) []string, publicKeys []string) error { | ||
authorizedKeysPath := ak.GetAuthorizedKeysPath() | ||
info, err := os.Stat(authorizedKeysPath) | ||
if err != nil { | ||
return tracerr.Wrap(err) | ||
} | ||
fileMode := info.Mode().Perm() | ||
|
||
authorizedKeysFile, err := os.OpenFile(authorizedKeysPath, os.O_RDWR, fileMode) | ||
if err != nil { | ||
return tracerr.Wrap(err) | ||
} | ||
defer authorizedKeysFile.Close() | ||
|
||
lines, err := ak.read(authorizedKeysFile) | ||
if err != nil { | ||
return tracerr.Wrap(err) | ||
} | ||
|
||
// write backup | ||
authorizedKeysPathBackup := ak.GetAuthorizedKeysPath() + ".bak" | ||
authorizedKeysBackup, err := os.OpenFile(authorizedKeysPathBackup, os.O_RDWR|os.O_CREATE|os.O_TRUNC, fileMode) | ||
if err != nil { | ||
return tracerr.Wrap(err) | ||
} | ||
defer authorizedKeysBackup.Close() | ||
if err := ak.write(authorizedKeysBackup, lines); err != nil { | ||
return tracerr.Wrap(err) | ||
} | ||
|
||
// transform lines | ||
newLines := transform(lines, publicKeys) | ||
|
||
// write authorized_keys | ||
if err := authorizedKeysFile.Truncate(0); err != nil { | ||
return tracerr.Wrap(err) | ||
} | ||
if _, err := authorizedKeysFile.Seek(0, 0); err != nil { | ||
return tracerr.Wrap(err) | ||
} | ||
if err := ak.write(authorizedKeysFile, newLines); err != nil { | ||
return tracerr.Wrap(err) | ||
} | ||
|
||
return nil | ||
} |
Oops, something went wrong.