• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

pgpainless / pgpainless / #1074

20 Jan 2026 11:18PM UTC coverage: 85.293% (+0.09%) from 85.206%
#1074

push

github

vanitasvitae
Bump sop-java to 15.0.0

6774 of 7942 relevant lines covered (85.29%)

0.85 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

82.05
/pgpainless-sop/src/main/kotlin/org/pgpainless/sop/ChangeKeyPasswordImpl.kt
1
// SPDX-FileCopyrightText: 2024 Paul Schaub <vanitasvitae@fsfe.org>
2
//
3
// SPDX-License-Identifier: Apache-2.0
4

5
package org.pgpainless.sop
6

7
import java.io.IOException
8
import java.io.InputStream
9
import java.io.OutputStream
10
import org.bouncycastle.openpgp.PGPException
11
import org.pgpainless.PGPainless
12
import org.pgpainless.exception.MissingPassphraseException
13
import org.pgpainless.key.protection.SecretKeyRingProtector
14
import org.pgpainless.key.util.KeyRingUtils
15
import org.pgpainless.util.OpenPGPCertificateUtil
16
import org.pgpainless.util.Passphrase
17
import sop.Ready
18
import sop.exception.SOPGPException
19
import sop.operation.ChangeKeyPassword
20

21
/** Implementation of the `change-key-password` operation using PGPainless. */
22
class ChangeKeyPasswordImpl(private val api: PGPainless) : ChangeKeyPassword {
1✔
23

24
    private val oldProtector = MatchMakingSecretKeyRingProtector()
1✔
25
    private var newPassphrase = Passphrase.emptyPassphrase()
1✔
26
    private var armor = true
1✔
27

28
    override fun keys(keys: InputStream): Ready {
29
        val newProtector = SecretKeyRingProtector.unlockAnyKeyWith(newPassphrase)
1✔
30
        val secretKeys =
1✔
31
            try {
1✔
32
                KeyReader(api).readSecretKeys(keys, true)
1✔
33
            } catch (e: IOException) {
×
34
                throw SOPGPException.BadData(e)
×
35
            }
36

37
        val updatedSecretKeys =
1✔
38
            secretKeys
1✔
39
                .map {
1✔
40
                    oldProtector.addSecretKey(it)
1✔
41
                    try {
1✔
42
                        return@map KeyRingUtils.changePassphrase(
1✔
43
                            null, it.pgpSecretKeyRing, oldProtector, newProtector)
1✔
44
                    } catch (e: MissingPassphraseException) {
1✔
45
                        throw SOPGPException.KeyIsProtected(
1✔
46
                            "Cannot unlock key ${it.keyIdentifier}", e)
1✔
47
                    } catch (e: PGPException) {
×
48
                        if (e.message?.contains("Exception decrypting key") == true) {
×
49
                            throw SOPGPException.KeyIsProtected(
×
50
                                "Cannot unlock key ${it.keyIdentifier}", e)
×
51
                        }
52
                        throw RuntimeException(
1✔
53
                            "Cannot change passphrase of key ${it.keyIdentifier}", e)
×
54
                    }
55
                }
56
                .map { api.toKey(it) }
1✔
57

58
        return object : Ready() {
1✔
59
            override fun writeTo(outputStream: OutputStream) {
60
                if (armor) {
1✔
61
                    OpenPGPCertificateUtil.armor(updatedSecretKeys, outputStream)
1✔
62
                } else {
63
                    OpenPGPCertificateUtil.encode(updatedSecretKeys, outputStream)
1✔
64
                }
65
            }
1✔
66
        }
67
    }
68

69
    override fun newKeyPassphrase(newPassphrase: String): ChangeKeyPassword = apply {
1✔
70
        this.newPassphrase = Passphrase.fromPassword(newPassphrase)
1✔
71
    }
1✔
72

73
    override fun noArmor(): ChangeKeyPassword = apply { armor = false }
1✔
74

75
    override fun oldKeyPassphrase(oldPassphrase: String): ChangeKeyPassword = apply {
1✔
76
        PasswordHelper.addPassphrasePlusRemoveWhitespace(oldPassphrase, oldProtector)
1✔
77
    }
1✔
78
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc