Skip to content

Commit

Permalink
#48 - Added functionality in order to show in the key details when a …
Browse files Browse the repository at this point in the history
…private key is password protected
  • Loading branch information
piratax007 committed Aug 3, 2022
1 parent 360e5cc commit 7dfb264
Show file tree
Hide file tree
Showing 15 changed files with 224 additions and 57 deletions.
5 changes: 5 additions & 0 deletions api/key_entry.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,8 @@ type PublicKeyEntry interface {
KeyEntry
WithDigestContent(func([]byte) []byte) []byte
}

type PrivateKeyEntry interface {
KeyEntry
IsPasswordProtected() bool
}
29 changes: 24 additions & 5 deletions gui/definitions/interface/KeyDetails.xml
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
</packing>
</child>
<child>
<!-- n-columns=2 n-rows=4 -->
<!-- n-columns=2 n-rows=5 -->
<object class="GtkGrid" id="keyDetailsGrid">
<property name="visible">True</property>
<property name="can-focus">False</property>
Expand Down Expand Up @@ -94,6 +94,25 @@
<style>
<class name="privateKey"/>
</style>
<child>
<object class="GtkLabel" id="passwordProtectedLabel">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="halign">start</property>
<property name="ellipsize">end</property>
<property name="label" translatable="yes">(password protected)</property>
<style>
<class name="passwordProtected"/>
</style>
</object>
<packing>
<property name="left-attach">1</property>
<property name="top-attach">2</property>
</packing>
</child>
<style>
<class name="privateKey"/>
</style>
<child>
<object class="GtkLabel" id="sha1FingerprintLabel">
<property name="visible">True</property>
Expand All @@ -106,7 +125,7 @@
</object>
<packing>
<property name="left-attach">0</property>
<property name="top-attach">2</property>
<property name="top-attach">3</property>
</packing>
</child>
<child>
Expand All @@ -123,7 +142,7 @@
</object>
<packing>
<property name="left-attach">1</property>
<property name="top-attach">2</property>
<property name="top-attach">3</property>
</packing>
</child>
<style>
Expand All @@ -141,7 +160,7 @@
</object>
<packing>
<property name="left-attach">0</property>
<property name="top-attach">3</property>
<property name="top-attach">4</property>
</packing>
</child>
<child>
Expand All @@ -158,7 +177,7 @@
</object>
<packing>
<property name="left-attach">1</property>
<property name="top-attach">3</property>
<property name="top-attach">4</property>
</packing>
</child>
<style>
Expand Down
5 changes: 5 additions & 0 deletions gui/definitions/styles/global.css
Original file line number Diff line number Diff line change
Expand Up @@ -114,4 +114,9 @@ window {

.fingerprint .fingerprintLabel {
padding-right: 10px;
}

.passwordProtected {
font-style: italic;
color: @theme_unfocused_fg_color;
}
16 changes: 16 additions & 0 deletions gui/key_details.go
Original file line number Diff line number Diff line change
Expand Up @@ -128,9 +128,25 @@ func (kd *keyDetails) displayFingerprint(fingerprintLabel, fingerprint string, f
}
}

const passwordProtectedLabel = "passwordProtectedLabel"

func (kd *keyDetails) privateKeyIsPasswordProtected() bool {
pk, ok := kd.key.(api.PrivateKeyEntry)
return ok && pk.IsPasswordProtected()
}

func (kd *keyDetails) displayIsPasswordProtected() {
if kd.privateKeyIsPasswordProtected() {
addClass(kd.box, "passwordProtectedPrivateKey")
} else {
kd.hide(passwordProtectedLabel)
}
}

func (kd *keyDetails) display() {
kd.displayLocations(kd.key.PublicKeyLocations(), publicKeyPath, publicKeyPathLabel)
kd.displayLocations(kd.key.PrivateKeyLocations(), privateKeyPath, privateKeyPathLabel)
kd.displayIsPasswordProtected()
kd.displayFingerprint(sha1FingerprintLabel, sha1Fingerprint, returningSlice20(sha1.Sum))
kd.displayFingerprint(sha256FingerprintLabel, sha256Fingerprint, returningSlice32(sha256.Sum256))
kd.setClassForKeyDetails()
Expand Down
12 changes: 12 additions & 0 deletions gui/key_details_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ func (s *guiSuite) Test_populateKeyDetails_createsTheKeyDetailsBoxAndDisplaysThe
builderKeyDetailsBoxMock.On("GetObject", "privateKeyPathLabel").Return(labelPrivateKeyPath, nil).Once()
pathPrivateKey := &gtk.MockLabel{}
builderKeyDetailsBoxMock.On("GetObject", "privateKeyPath").Return(pathPrivateKey, nil).Once()
labelPasswordProtected := &gtk.MockLabel{}
builderKeyDetailsBoxMock.On("GetObject", "passwordProtectedLabel").Return(labelPasswordProtected, nil).Once()

fingerprintSha1 := &gtk.MockLabel{}
fingerprintSha256 := &gtk.MockLabel{}
Expand All @@ -50,6 +52,7 @@ func (s *guiSuite) Test_populateKeyDetails_createsTheKeyDetailsBoxAndDisplaysThe
pathPublicKeyPath.On("SetTooltipText", "/a/path/to/a/public/key").Return().Once()
labelPrivateKeyPath.On("Hide").Return().Once()
pathPrivateKey.On("Hide").Return().Once()
labelPasswordProtected.On("Hide").Return().Once()

fingerprintSha1.On("SetLabel", "AB:CD:10").Return().Once()
fingerprintSha1.On("SetTooltipText", "AB:CD:10").Return().Once()
Expand All @@ -67,6 +70,7 @@ func (s *guiSuite) Test_populateKeyDetails_createsTheKeyDetailsBoxAndDisplaysThe
pathPublicKeyPath.AssertExpectations(s.T())
labelPrivateKeyPath.AssertExpectations(s.T())
pathPrivateKey.AssertExpectations(s.T())
labelPasswordProtected.AssertExpectations(s.T())
fingerprintSha1.AssertExpectations(s.T())
fingerprintSha256.AssertExpectations(s.T())
scMock.AssertExpectations(s.T())
Expand All @@ -82,6 +86,8 @@ func (s *guiSuite) Test_populateKeyDetails_createsTheKeyDetailsBoxAndDisplaysThe

pathPrivateKey := &gtk.MockLabel{}
builderKeyDetailsBoxMock.On("GetObject", "privateKeyPath").Return(pathPrivateKey, nil).Once()
labelPasswordProtected := &gtk.MockLabel{}
builderKeyDetailsBoxMock.On("GetObject", "passwordProtectedLabel").Return(labelPasswordProtected, nil).Once()

labelPublicKeyPath := &gtk.MockLabel{}
builderKeyDetailsBoxMock.On("GetObject", "publicKeyPathLabel").Return(labelPublicKeyPath, nil).Once()
Expand All @@ -104,6 +110,7 @@ func (s *guiSuite) Test_populateKeyDetails_createsTheKeyDetailsBoxAndDisplaysThe
keMock.On("KeyType").Return(api.PrivateKeyType).Once()
pathPrivateKey.On("SetLabel", "/a/path/to/a/private/key").Return().Once()
pathPrivateKey.On("SetTooltipText", "/a/path/to/a/private/key").Return().Once()
labelPasswordProtected.On("Hide").Return().Once()
labelPublicKeyPath.On("Hide").Return().Once()
pathPublicKey.On("Hide").Return().Once()
labelSha1Fingerprint.On("Hide").Return().Once()
Expand All @@ -119,6 +126,7 @@ func (s *guiSuite) Test_populateKeyDetails_createsTheKeyDetailsBoxAndDisplaysThe
keyDetailsHolder.AssertExpectations(s.T())
keMock.AssertExpectations(s.T())
pathPrivateKey.AssertExpectations(s.T())
labelPasswordProtected.AssertExpectations(s.T())
labelPublicKeyPath.AssertExpectations(s.T())
pathPublicKey.AssertExpectations(s.T())
labelSha1Fingerprint.AssertExpectations(s.T())
Expand All @@ -141,6 +149,8 @@ func (s *guiSuite) Test_populateKeyDetails_createsTheKeyDetailsBoxAndDisplaysBot

pathPrivateKey := &gtk.MockLabel{}
builderKeyDetailsBoxMock.On("GetObject", "privateKeyPath").Return(pathPrivateKey, nil).Once()
labelPasswordProtected := &gtk.MockLabel{}
builderKeyDetailsBoxMock.On("GetObject", "passwordProtectedLabel").Return(labelPasswordProtected, nil).Once()

labelFingerprintSha1 := &gtk.MockLabel{}
builderKeyDetailsBoxMock.On("GetObject", "sha1FingerprintLabel").Return(labelFingerprintSha1, nil).Once()
Expand All @@ -160,6 +170,7 @@ func (s *guiSuite) Test_populateKeyDetails_createsTheKeyDetailsBoxAndDisplaysBot
pathPublicKey.On("SetTooltipText", "/a/path/to/a/public/key").Return().Once()
pathPrivateKey.On("SetLabel", "/a/path/to/a/private/key").Return().Once()
pathPrivateKey.On("SetTooltipText", "/a/path/to/a/private/key").Return().Once()
labelPasswordProtected.On("Hide").Return().Once()
labelFingerprintSha1.On("Hide").Return().Once()
fingerprintSha1.On("Hide").Return().Once()
labelFingerprintSha256.On("Hide").Return().Once()
Expand All @@ -174,6 +185,7 @@ func (s *guiSuite) Test_populateKeyDetails_createsTheKeyDetailsBoxAndDisplaysBot
keMock.AssertExpectations(s.T())
pathPublicKey.AssertExpectations(s.T())
pathPrivateKey.AssertExpectations(s.T())
labelPasswordProtected.AssertExpectations(s.T())
labelFingerprintSha1.AssertExpectations(s.T())
fingerprintSha1.AssertExpectations(s.T())
fingerprintSha256.AssertExpectations(s.T())
Expand Down
5 changes: 0 additions & 5 deletions gui/key_list.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,6 @@ func (u *ui) createKeyEntryBoxFrom(entry api.KeyEntry, detailsBox gtki.Box, deta
b, builder := buildObjectFrom[gtki.Button](u, "KeyListEntry")
builder.get("keyListEntryLabel").(gtki.Label).SetLabel(entry.Locations()[0])
b.Connect("clicked", func() {
// We have several possibilities:
// - no box is currently visible because we just started the program
// - no box is visible because it was previously collapsed
// - the box is visible with information about another key
// - the box is visible with information about the same key as currently clicked
u.populateKeyDetails(entry, detailsBox)

if u.currentlyVisibleKeyEntryButton != nil {
Expand Down
4 changes: 4 additions & 0 deletions gui/key_list_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,8 @@ func (s *guiSuite) Test_createKeyEntryBoxFrom_CreatesAGTKIBoxWithTheGivenASSHKey
builderKeyDetailsBoxMock.On("GetObject", "privateKeyPath").Return(pathPrivateKey, nil).Once()
labelPrivateKeyPath := &gtk.MockLabel{}
builderKeyDetailsBoxMock.On("GetObject", "privateKeyPathLabel").Return(labelPrivateKeyPath, nil).Once()
labelPasswordProtected := &gtk.MockLabel{}
builderKeyDetailsBoxMock.On("GetObject", "passwordProtectedLabel").Return(labelPasswordProtected, nil).Once()

keyEntry.On("PublicKeyLocations").Return([]string{"/a/path/to/a/public/key"}).Once()
keyEntry.On("PrivateKeyLocations").Return(nil).Once()
Expand All @@ -104,6 +106,7 @@ func (s *guiSuite) Test_createKeyEntryBoxFrom_CreatesAGTKIBoxWithTheGivenASSHKey

pathPrivateKey.On("Hide").Return().Once()
labelPrivateKeyPath.On("Hide").Return().Once()
labelPasswordProtected.On("Hide").Return().Once()

labelFingerprintSha1 := &gtk.MockLabel{}
builderKeyDetailsBoxMock.On("GetObject", "sha1FingerprintLabel").Return(labelFingerprintSha1, nil).Once()
Expand Down Expand Up @@ -132,6 +135,7 @@ func (s *guiSuite) Test_createKeyEntryBoxFrom_CreatesAGTKIBoxWithTheGivenASSHKey
scMock1.AssertExpectations(s.T())
scMock2.AssertExpectations(s.T())
pathPrivateKey.AssertExpectations(s.T())
labelPasswordProtected.AssertExpectations(s.T())
labelPrivateKeyPath.AssertExpectations(s.T())
labelFingerprintSha1.AssertExpectations(s.T())
labelFingerprintSha256.AssertExpectations(s.T())
Expand Down
8 changes: 4 additions & 4 deletions ssh/ed25519_file_reader.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,10 @@ func (a *access) filesContainingEd25519PrivateKeys(fileNameList []string) []stri
return result
}

func checkIfFileContainsAPublicEd25519Key(fileName string) (bool, error) {
return fileContentMatches(fileName, isEd25519PublicKey)
func ed25519PublicKeyFrom(fileNameList []string) []*publicKey {
return filter(transform(fileNameList, publicKeyFromFile), both(not(isNil[publicKey]), (*publicKey).isEd25519))
}

func filesContainingEd25519PublicKeys(fileNameList []string) []string {
return filter(fileNameList, ignoringErrors(checkIfFileContainsAPublicEd25519Key))
func (a *access) ed25519PrivateKeyFrom(fileNameList []string) []*privateKey {
return filter(transform(fileNameList, a.privateKeyFromFile), both(not(isNil[privateKey]), (*privateKey).isEd25519))
}
8 changes: 0 additions & 8 deletions ssh/ed25519_key_reader.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,3 @@ func (a *access) isEd25519PrivateKey(pk string) bool {
func (k *publicKey) isEd25519() bool {
return k.isAlgorithm(ed25519Algorithm)
}

func isEd25519PublicKey(k string) bool {
pub, ok := parsePublicKey(k)
if !ok {
return false
}
return pub.isEd25519()
}
20 changes: 14 additions & 6 deletions ssh/file_reader.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,20 +45,28 @@ func createPrivateKeyRepresentationsFrom(input []string) []*privateKeyRepresenta
return transform(input, createPrivateKeyRepresentation)
}

func createPrivateKeyRepresentationFromPrivateKeys(input []*privateKey) []*privateKeyRepresentation {
return transform(input, createPrivateKeyRepresentationFromPrivateKey)
}

func (a *access) privateKeyRepresentationsFrom(input []string) []*privateKeyRepresentation {
privateKeyFiles := concat(
a.filesContainingRSAPrivateKeys(input),
a.filesContainingEd25519PrivateKeys(input),
)
rsaKeys := a.rsaPrivateKeyFrom(input)
rsaKeyRepresentations := createPrivateKeyRepresentationFromPrivateKeys(rsaKeys)

ed25519Keys := a.ed25519PrivateKeyFrom(input)
ed25519KeyRepresentations := createPrivateKeyRepresentationFromPrivateKeys(ed25519Keys)

return createPrivateKeyRepresentationsFrom(privateKeyFiles)
return concat(
rsaKeyRepresentations,
ed25519KeyRepresentations,
)
}

func publicKeyRepresentationsFrom(input []string) []*publicKeyRepresentation {
rsaKeys := rsaPublicKeysFrom(input)
rsaKeyRepresentations := createPublicKeyRepresentationsFromPublicKeys(rsaKeys)

ed25519Keys := ed25519KeyFrom(input)
ed25519Keys := ed25519PublicKeyFrom(input)
ed25519KeyRepresentations := createPublicKeyRepresentationsFromPublicKeys(ed25519Keys)

return concat(
Expand Down
12 changes: 8 additions & 4 deletions ssh/file_reader_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -370,11 +370,11 @@ func (s *sshSuite) Test_createPrivateKeyEntriesFrom_ReturnsAListOfKeyEntriesFrom

paths = []string{"a path"}
l = createPrivateKeyRepresentationsFrom(paths)
s.Equal([]*privateKeyRepresentation{{"a path"}}, l)
s.Equal([]*privateKeyRepresentation{{"a path", false}}, l)

paths = []string{"a path", "another path"}
l = createPrivateKeyRepresentationsFrom(paths)
s.Equal([]*privateKeyRepresentation{{"a path"}, {"another path"}}, l)
s.Equal([]*privateKeyRepresentation{{"a path", false}, {"another path", false}}, l)
}

func (s *sshSuite) Test_privateKeyEntriesFrom_ReturnsAListOfPrivateKeyEntriesFromAllTheProvidedPaths() {
Expand Down Expand Up @@ -402,18 +402,22 @@ func (s *sshSuite) Test_privateKeyEntriesFrom_ReturnsAListOfPrivateKeyEntriesFro
s.createFileWithContent(s.tdir, privateRSAKeyFile1, correctRSASSHPrivateKey)
privateRSAKeyFile2 := "Another-file-with-another-private-RSA-key"
s.createFileWithContent(s.tdir, privateRSAKeyFile2, correctRSASSHPrivateKeyOther)
privateRSAKeyFile3Protected := "a password protected RSA key"
s.createFileWithContent(s.tdir, privateRSAKeyFile3Protected, correctRSAPasswordProtectedKey)

paths = []string{
filepath.Join(s.tdir, emptyFile),
filepath.Join(s.tdir, notAnRSAPrivateKeyFile),
filepath.Join(s.tdir, privateRSAKeyFile1),
filepath.Join(s.tdir, privateRSAKeyFile2),
filepath.Join(s.tdir, privateRSAKeyFile3Protected),
}

l = a.privateKeyRepresentationsFrom(paths)
s.Equal([]*privateKeyRepresentation{
createPrivateKeyRepresentation(filepath.Join(s.tdir, privateRSAKeyFile1)),
createPrivateKeyRepresentation(filepath.Join(s.tdir, privateRSAKeyFile2)),
{filepath.Join(s.tdir, privateRSAKeyFile1), false},
{filepath.Join(s.tdir, privateRSAKeyFile2), false},
{filepath.Join(s.tdir, privateRSAKeyFile3Protected), true},
}, l)
}

Expand Down
Loading

0 comments on commit 7dfb264

Please sign in to comment.