mirror of
https://github.com/maxgoedjen/secretive.git
synced 2026-04-10 03:07:22 +02:00
Compare commits
7 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c8cf0db1c5 | ||
|
|
412687467b | ||
|
|
416a7d5f40 | ||
|
|
c4605fb60e | ||
|
|
61eed5987c | ||
|
|
cbef7c6181 | ||
|
|
63a09390b8 |
21
.github/workflows/nightly.yml
vendored
21
.github/workflows/nightly.yml
vendored
@@ -3,10 +3,16 @@ name: Nightly
|
|||||||
on:
|
on:
|
||||||
schedule:
|
schedule:
|
||||||
- cron: "0 8 * * *"
|
- cron: "0 8 * * *"
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build:
|
build:
|
||||||
# runs-on: macOS-latest
|
# runs-on: macOS-latest
|
||||||
runs-on: macos-15
|
runs-on: macos-15
|
||||||
|
permissions:
|
||||||
|
id-token: write
|
||||||
|
contents: write
|
||||||
|
attestations: write
|
||||||
timeout-minutes: 10
|
timeout-minutes: 10
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v5
|
- uses: actions/checkout@v5
|
||||||
@@ -30,22 +36,23 @@ jobs:
|
|||||||
sed -i '' -e "s/GITHUB_BUILD_URL/https:\/\/github.com\/maxgoedjen\/secretive\/actions\/runs\/$RUN_ID/g" Sources/Secretive/Credits.rtf
|
sed -i '' -e "s/GITHUB_BUILD_URL/https:\/\/github.com\/maxgoedjen\/secretive\/actions\/runs\/$RUN_ID/g" Sources/Secretive/Credits.rtf
|
||||||
- name: Build
|
- name: Build
|
||||||
run: xcrun xcodebuild -project Sources/Secretive.xcodeproj -scheme Secretive -configuration Release -archivePath Archive.xcarchive archive
|
run: xcrun xcodebuild -project Sources/Secretive.xcodeproj -scheme Secretive -configuration Release -archivePath Archive.xcarchive archive
|
||||||
- name: Create ZIPs
|
- name: Create ZIP
|
||||||
run: |
|
run: |
|
||||||
ditto -c -k --sequesterRsrc --keepParent Archive.xcarchive/Products/Applications/Secretive.app ./Secretive.zip
|
ditto -c -k --sequesterRsrc --keepParent Archive.xcarchive/Products/Applications/Secretive.app ./Secretive.zip
|
||||||
ditto -c -k --sequesterRsrc --keepParent Archive.xcarchive ./Archive.zip
|
|
||||||
- name: Notarize
|
- name: Notarize
|
||||||
env:
|
env:
|
||||||
APPLE_API_KEY_ID: ${{ secrets.APPLE_API_KEY_ID }}
|
APPLE_API_KEY_ID: ${{ secrets.APPLE_API_KEY_ID }}
|
||||||
APPLE_API_ISSUER: ${{ secrets.APPLE_API_ISSUER }}
|
APPLE_API_ISSUER: ${{ secrets.APPLE_API_ISSUER }}
|
||||||
run: xcrun notarytool submit --key ~/.private_keys/AuthKey_$APPLE_API_KEY_ID.p8 --key-id $APPLE_API_KEY_ID --issuer $APPLE_API_ISSUER Secretive.zip
|
run: xcrun notarytool submit --key ~/.private_keys/AuthKey_$APPLE_API_KEY_ID.p8 --key-id $APPLE_API_KEY_ID --issuer $APPLE_API_ISSUER Secretive.zip
|
||||||
- name: Attest
|
|
||||||
id: attest
|
|
||||||
uses: actions/attest-build-provenance@v2
|
|
||||||
with:
|
|
||||||
subject-path: 'Secretive.zip'
|
|
||||||
- name: Upload App to Artifacts
|
- name: Upload App to Artifacts
|
||||||
|
id: upload
|
||||||
uses: actions/upload-artifact@v4
|
uses: actions/upload-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: Secretive.zip
|
name: Secretive.zip
|
||||||
path: Secretive.zip
|
path: Secretive.zip
|
||||||
|
- name: Attest
|
||||||
|
id: attest
|
||||||
|
uses: actions/attest-build-provenance@v2
|
||||||
|
with:
|
||||||
|
subject-name: "Secretive.zip"
|
||||||
|
subject-digest: sha256:${{ steps.upload.outputs.artifact-digest }}
|
||||||
|
|||||||
23
.github/workflows/release.yml
vendored
23
.github/workflows/release.yml
vendored
@@ -56,39 +56,34 @@ jobs:
|
|||||||
sed -i '' -e "s/GITHUB_BUILD_URL/https:\/\/github.com\/maxgoedjen\/secretive\/actions\/runs\/$RUN_ID/g" Sources/Secretive/Credits.rtf
|
sed -i '' -e "s/GITHUB_BUILD_URL/https:\/\/github.com\/maxgoedjen\/secretive\/actions\/runs\/$RUN_ID/g" Sources/Secretive/Credits.rtf
|
||||||
- name: Build
|
- name: Build
|
||||||
run: xcrun xcodebuild -project Sources/Secretive.xcodeproj -scheme Secretive -configuration Release -archivePath Archive.xcarchive archive
|
run: xcrun xcodebuild -project Sources/Secretive.xcodeproj -scheme Secretive -configuration Release -archivePath Archive.xcarchive archive
|
||||||
- name: Create ZIPs
|
- name: Create ZIP
|
||||||
run: |
|
run: |
|
||||||
ditto -c -k --sequesterRsrc --keepParent Archive.xcarchive/Products/Applications/Secretive.app ./Secretive.zip
|
ditto -c -k --sequesterRsrc --keepParent Archive.xcarchive/Products/Applications/Secretive.app ./Secretive.zip
|
||||||
ditto -c -k --sequesterRsrc --keepParent Archive.xcarchive ./Xcode_Archive.zip
|
|
||||||
- name: Notarize
|
- name: Notarize
|
||||||
env:
|
env:
|
||||||
APPLE_API_KEY_ID: ${{ secrets.APPLE_API_KEY_ID }}
|
APPLE_API_KEY_ID: ${{ secrets.APPLE_API_KEY_ID }}
|
||||||
APPLE_API_ISSUER: ${{ secrets.APPLE_API_ISSUER }}
|
APPLE_API_ISSUER: ${{ secrets.APPLE_API_ISSUER }}
|
||||||
run: xcrun notarytool submit --key ~/.private_keys/AuthKey_$APPLE_API_KEY_ID.p8 --key-id $APPLE_API_KEY_ID --issuer $APPLE_API_ISSUER Secretive.zip
|
run: xcrun notarytool submit --key ~/.private_keys/AuthKey_$APPLE_API_KEY_ID.p8 --key-id $APPLE_API_KEY_ID --issuer $APPLE_API_ISSUER Secretive.zip
|
||||||
|
- name: Upload App to Artifacts
|
||||||
|
id: upload
|
||||||
|
uses: actions/upload-artifact@v4
|
||||||
|
with:
|
||||||
|
name: Secretive.zip
|
||||||
|
path: Secretive.zip
|
||||||
- name: Attest
|
- name: Attest
|
||||||
id: attest
|
id: attest
|
||||||
uses: actions/attest-build-provenance@v2
|
uses: actions/attest-build-provenance@v2
|
||||||
with:
|
with:
|
||||||
subject-path: 'Secretive.zip, Xcode_Archive.zip'
|
subject-name: "Secretive.zip"
|
||||||
|
subject-digest: ${{ steps.upload.outputs.artifact-digest }}
|
||||||
- name: Create Release
|
- name: Create Release
|
||||||
run: |
|
run: |
|
||||||
sed -i.tmp "s/RUN_ID/$RUN_ID/g" .github/templates/release.md
|
sed -i.tmp "s/RUN_ID/$RUN_ID/g" .github/templates/release.md
|
||||||
sed -i.tmp "s/ATTESTATION_ID/$ATTESTATION_ID/g" .github/templates/release.md
|
sed -i.tmp "s/ATTESTATION_ID/$ATTESTATION_ID/g" .github/templates/release.md
|
||||||
gh release create $TAG_NAME -d -F .github/templates/release.md
|
gh release create $TAG_NAME -d -F .github/templates/release.md
|
||||||
gh release upload Secretive.zip
|
gh release upload Secretive.zip
|
||||||
gh release upload Xcode_Archive.zip
|
|
||||||
env:
|
env:
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
TAG_NAME: ${{ github.ref }}
|
TAG_NAME: ${{ github.ref }}
|
||||||
RUN_ID: ${{ github.run_id }}
|
RUN_ID: ${{ github.run_id }}
|
||||||
ATTESTATION_ID: ${{ steps.attest.outputs.attestation-id }}
|
ATTESTATION_ID: ${{ steps.attest.outputs.attestation-id }}
|
||||||
- name: Upload App to Artifacts
|
|
||||||
uses: actions/upload-artifact@v4
|
|
||||||
with:
|
|
||||||
name: Secretive.zip
|
|
||||||
path: Secretive.zip
|
|
||||||
- name: Upload Archive to Artifacts
|
|
||||||
uses: actions/upload-artifact@v4
|
|
||||||
with:
|
|
||||||
name: Xcode_Archive.zip
|
|
||||||
path: Xcode_Archive.zip
|
|
||||||
|
|||||||
@@ -3403,28 +3403,6 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"integrations_public_key_path_placeholder" : {
|
|
||||||
"extractionState" : "manual",
|
|
||||||
"localizations" : {
|
|
||||||
"en" : {
|
|
||||||
"stringUnit" : {
|
|
||||||
"state" : "translated",
|
|
||||||
"value" : "YOUR_PUBLIC_KEY_PATH"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"integrations_public_key_placeholder" : {
|
|
||||||
"extractionState" : "manual",
|
|
||||||
"localizations" : {
|
|
||||||
"en" : {
|
|
||||||
"stringUnit" : {
|
|
||||||
"state" : "translated",
|
|
||||||
"value" : "YOUR_PUBLIC_KEY"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"integrations_shell_section_title" : {
|
"integrations_shell_section_title" : {
|
||||||
"extractionState" : "manual",
|
"extractionState" : "manual",
|
||||||
"localizations" : {
|
"localizations" : {
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ extension SecureEnclave {
|
|||||||
SecItemCopyMatching(privateAttributes, &privateUntyped)
|
SecItemCopyMatching(privateAttributes, &privateUntyped)
|
||||||
guard let privateTyped = privateUntyped as? [[CFString: Any]] else { return }
|
guard let privateTyped = privateUntyped as? [[CFString: Any]] else { return }
|
||||||
let migratedPublicKeys = Set(store.secrets.map(\.publicKey))
|
let migratedPublicKeys = Set(store.secrets.map(\.publicKey))
|
||||||
var migrated = false
|
var migratedAny = false
|
||||||
for key in privateTyped {
|
for key in privateTyped {
|
||||||
let name = key[kSecAttrLabel] as? String ?? String(localized: .unnamedSecret)
|
let name = key[kSecAttrLabel] as? String ?? String(localized: .unnamedSecret)
|
||||||
let id = key[kSecAttrApplicationLabel] as! Data
|
let id = key[kSecAttrApplicationLabel] as! Data
|
||||||
@@ -45,20 +45,24 @@ extension SecureEnclave {
|
|||||||
// Best guess.
|
// Best guess.
|
||||||
let auth: AuthenticationRequirement = String(describing: accessControl)
|
let auth: AuthenticationRequirement = String(describing: accessControl)
|
||||||
.contains("DeviceOwnerAuthentication") ? .presenceRequired : .unknown
|
.contains("DeviceOwnerAuthentication") ? .presenceRequired : .unknown
|
||||||
let parsed = try CryptoKit.SecureEnclave.P256.Signing.PrivateKey(dataRepresentation: tokenObjectID)
|
do {
|
||||||
let secret = Secret(id: UUID().uuidString, name: name, publicKey: parsed.publicKey.x963Representation, attributes: Attributes(keyType: .init(algorithm: .ecdsa, size: 256), authentication: auth))
|
let parsed = try CryptoKit.SecureEnclave.P256.Signing.PrivateKey(dataRepresentation: tokenObjectID)
|
||||||
guard !migratedPublicKeys.contains(parsed.publicKey.x963Representation) else {
|
let secret = Secret(id: UUID().uuidString, name: name, publicKey: parsed.publicKey.x963Representation, attributes: Attributes(keyType: .init(algorithm: .ecdsa, size: 256), authentication: auth))
|
||||||
logger.log("Skipping \(name), public key already present. Marking as migrated.")
|
guard !migratedPublicKeys.contains(parsed.publicKey.x963Representation) else {
|
||||||
|
logger.log("Skipping \(name), public key already present. Marking as migrated.")
|
||||||
|
try markMigrated(secret: secret, oldID: id)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
logger.log("Migrating \(name).")
|
||||||
|
try store.saveKey(tokenObjectID, name: name, attributes: secret.attributes)
|
||||||
|
logger.log("Migrated \(name).")
|
||||||
try markMigrated(secret: secret, oldID: id)
|
try markMigrated(secret: secret, oldID: id)
|
||||||
continue
|
migratedAny = true
|
||||||
|
} catch {
|
||||||
|
logger.error("Failed to migrate \(name): \(error).")
|
||||||
}
|
}
|
||||||
logger.log("Migrating \(name).")
|
|
||||||
try store.saveKey(tokenObjectID, name: name, attributes: secret.attributes)
|
|
||||||
logger.log("Migrated \(name).")
|
|
||||||
try markMigrated(secret: secret, oldID: id)
|
|
||||||
migrated = true
|
|
||||||
}
|
}
|
||||||
if migrated {
|
if migratedAny {
|
||||||
store.reloadSecrets()
|
store.reloadSecrets()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -146,6 +146,6 @@ struct CreateSecretView<StoreType: SecretStoreModifiable>: View {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#Preview {
|
//#Preview {
|
||||||
CreateSecretView(store: Preview.StoreModifiable()) { _ in }
|
// CreateSecretView(store: Preview.StoreModifiable()) { _ in }
|
||||||
}
|
//}
|
||||||
|
|||||||
@@ -57,15 +57,10 @@ struct EmptyStoreModifiableView: View {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#if DEBUG
|
|
||||||
|
|
||||||
struct EmptyStoreModifiableView_Previews: PreviewProvider {
|
#Preview {
|
||||||
static var previews: some View {
|
EmptyStoreImmutableView()
|
||||||
Group {
|
}
|
||||||
EmptyStoreImmutableView()
|
#Preview {
|
||||||
EmptyStoreModifiableView()
|
EmptyStoreModifiableView()
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|||||||
@@ -13,12 +13,7 @@ struct NoStoresView: View {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#if DEBUG
|
#Preview {
|
||||||
|
NoStoresView()
|
||||||
struct NoStoresView_Previews: PreviewProvider {
|
|
||||||
static var previews: some View {
|
|
||||||
NoStoresView()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|||||||
@@ -37,6 +37,6 @@ struct SecretDetailView<SecretType: Secret>: View {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#Preview {
|
//#Preview {
|
||||||
SecretDetailView(secret: Preview.Secret(name: "Demonstration Secret"))
|
// SecretDetailView(secret: Preview.Secret(name: "Demonstration Secret"))
|
||||||
}
|
//}
|
||||||
|
|||||||
@@ -143,11 +143,11 @@ struct AgentNotRunningView: View {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#Preview {
|
//#Preview {
|
||||||
AgentStatusView()
|
// AgentStatusView()
|
||||||
.environment(\.agentStatusChecker, PreviewAgentStatusChecker(running: false))
|
// .environment(\.agentStatusChecker, PreviewAgentStatusChecker(running: false))
|
||||||
}
|
//}
|
||||||
#Preview {
|
//#Preview {
|
||||||
AgentStatusView()
|
// AgentStatusView()
|
||||||
.environment(\.agentStatusChecker, PreviewAgentStatusChecker(running: true, process: .current))
|
// .environment(\.agentStatusChecker, PreviewAgentStatusChecker(running: true, process: .current))
|
||||||
}
|
//}
|
||||||
|
|||||||
@@ -198,25 +198,17 @@ extension ContentView {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#if DEBUG
|
|
||||||
|
|
||||||
struct ContentView_Previews: PreviewProvider {
|
|
||||||
|
|
||||||
static var previews: some View {
|
|
||||||
Group {
|
|
||||||
// Empty on modifiable and nonmodifiable
|
|
||||||
ContentView(showingCreation: .constant(false), runningSetup: .constant(false), hasRunSetup: .constant(true))
|
|
||||||
.environment(Preview.storeList(stores: [Preview.Store(numberOfRandomSecrets: 0)], modifiableStores: [Preview.StoreModifiable(numberOfRandomSecrets: 0)]))
|
|
||||||
.environment(PreviewUpdater())
|
|
||||||
|
|
||||||
// 5 items on modifiable and nonmodifiable
|
|
||||||
ContentView(showingCreation: .constant(false), runningSetup: .constant(false), hasRunSetup: .constant(true))
|
|
||||||
.environment(Preview.storeList(stores: [Preview.Store()], modifiableStores: [Preview.StoreModifiable()]))
|
|
||||||
.environment(PreviewUpdater())
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
//#Preview {
|
||||||
|
// // Empty on modifiable and nonmodifiable
|
||||||
|
// ContentView(showingCreation: .constant(false), runningSetup: .constant(false), hasRunSetup: .constant(true))
|
||||||
|
// .environment(Preview.storeList(stores: [Preview.Store(numberOfRandomSecrets: 0)], modifiableStores: [Preview.StoreModifiable(numberOfRandomSecrets: 0)]))
|
||||||
|
// .environment(PreviewUpdater())
|
||||||
|
//}
|
||||||
|
//
|
||||||
|
//#Preview {
|
||||||
|
// // 5 items on modifiable and nonmodifiable
|
||||||
|
// ContentView(showingCreation: .constant(false), runningSetup: .constant(false), hasRunSetup: .constant(true))
|
||||||
|
// .environment(Preview.storeList(stores: [Preview.Store()], modifiableStores: [Preview.StoreModifiable()]))
|
||||||
|
// .environment(PreviewUpdater())
|
||||||
|
//}
|
||||||
|
|||||||
@@ -163,17 +163,12 @@ fileprivate struct BackgroundViewModifier: ViewModifier {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#if DEBUG
|
#Preview {
|
||||||
|
CopyableView(title: .secretDetailSha256FingerprintLabel, image: Image(systemName: "figure.wave"), text: "Hello world.")
|
||||||
struct CopyableView_Previews: PreviewProvider {
|
.padding()
|
||||||
static var previews: some View {
|
|
||||||
Group {
|
|
||||||
CopyableView(title: .secretDetailSha256FingerprintLabel, image: Image(systemName: "figure.wave"), text: "Hello world.")
|
|
||||||
.padding()
|
|
||||||
CopyableView(title: .secretDetailSha256FingerprintLabel, image: Image(systemName: "figure.wave"), text: "Long text. Long text. Long text. Long text. Long text. Long text. Long text. Long text. Long text. Long text. Long text. Long text. Long text. Long text. Long text. Long text. Long text. Long text. Long text. Long text. Long text. Long text. Long text. Long text. Long text. Long text. Long text. Long text. Long text. ")
|
|
||||||
.padding()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#Preview {
|
||||||
|
CopyableView(title: .secretDetailSha256FingerprintLabel, image: Image(systemName: "figure.wave"), text: "Long text. Long text. Long text. Long text. Long text. Long text. Long text. Long text. Long text. Long text. Long text. Long text. Long text. Long text. Long text. Long text. Long text. Long text. Long text. Long text. Long text. Long text. Long text. Long text. Long text. Long text. Long text. Long text. Long text. ")
|
||||||
|
.padding()
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user