Skip to content

Commit

Permalink
✨ Create a tooltip for clipevery to interact with keychain (#24)
Browse files Browse the repository at this point in the history
  • Loading branch information
guiyanakuang authored Nov 21, 2023
1 parent 264424d commit 95070bf
Show file tree
Hide file tree
Showing 7 changed files with 162 additions and 15 deletions.
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package com.clipevery.macos

import com.clipevery.clip.ClipboardService
import com.clipevery.macos.api.MacClipboard
import com.clipevery.macos.api.MacosApi
import java.awt.Toolkit
import java.awt.datatransfer.Clipboard
import java.awt.datatransfer.Transferable
Expand All @@ -22,7 +22,7 @@ class MacosClipboardService

override fun run() {
try {
MacClipboard.INSTANCE.clipboardChangeCount.let { currentChangeCount ->
MacosApi.INSTANCE.getClipboardChangeCount().let { currentChangeCount ->
if (changeCount == currentChangeCount) {
return
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package com.clipevery.macos

import com.clipevery.macos.api.MacosApi

object MacosKeychainHelper {

fun getPassword(service: String, account: String): String? {
return MacosApi.INSTANCE.getPassword(service, account)
}

fun setPassword(service: String, account: String, password: String): Boolean {
return MacosApi.INSTANCE.setPassword(service, account, password)
}

fun updatePassword(service: String, account: String, password: String): Boolean {
return MacosApi.INSTANCE.updatePassword(service, account, password)
}

fun deletePassword(service: String, account: String): Boolean {
return MacosApi.INSTANCE.deletePassword(service, account)
}
}

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package com.clipevery.macos.api

import com.sun.jna.Library
import com.sun.jna.Native

interface MacosApi : Library {

fun getClipboardChangeCount(): Int

fun getPassword(service: String, account: String): String?

fun setPassword(service: String, account: String, password: String): Boolean

fun updatePassword(service: String, account: String, password: String): Boolean

fun deletePassword(service: String, account: String): Boolean

companion object {
val INSTANCE: MacosApi = Native.load("MacosApi", MacosApi::class.java)
}
}
Binary file not shown.
93 changes: 93 additions & 0 deletions composeApp/src/desktopMain/swift/MacosApi.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
import Cocoa
import Foundation
import Security

@_cdecl("getClipboardChangeCount")
public func getClipboardChangeCount() -> Int {
let pasteboard = NSPasteboard.general
return pasteboard.changeCount
}

@_cdecl("getPassword")
public func getPassword(service: UnsafePointer<CChar>, account: UnsafePointer<CChar>) -> UnsafePointer<CChar>? {
let serviceString = String(cString: service)
let accountString = String(cString: account)

let query: [String: Any] = [
kSecClass as String: kSecClassGenericPassword,
kSecAttrService as String: serviceString,
kSecAttrAccount as String: accountString,
kSecReturnData as String: kCFBooleanTrue!,
kSecMatchLimit as String: kSecMatchLimitOne
]

var item: CFTypeRef?
let status = SecItemCopyMatching(query as CFDictionary, &item)

guard status == errSecSuccess else { return nil }

if let data = item as? Data, let password = String(data: data, encoding: .utf8) {
return UnsafePointer<CChar>(strdup(password))
}

return nil
}

@_cdecl("setPassword")
public func setPassword(service: UnsafePointer<CChar>, account: UnsafePointer<CChar>, password: UnsafePointer<CChar>) -> Bool {
let serviceString = String(cString: service)
let accountString = String(cString: account)
let passwordString = String(cString: password)

let passwordData = passwordString.data(using: .utf8)!

let query: [String: Any] = [
kSecClass as String: kSecClassGenericPassword,
kSecAttrService as String: serviceString,
kSecAttrAccount as String: accountString,
kSecValueData as String: passwordData
]

// Try to add the item to the keychain
let status = SecItemAdd(query as CFDictionary, nil)

// Check the result
return status == errSecSuccess
}

@_cdecl("updatePassword")
public func updatePassword(service: UnsafePointer<CChar>, account: UnsafePointer<CChar>, newPassword: UnsafePointer<CChar>) -> Bool {
let serviceString = String(cString: service)
let accountString = String(cString: account)
let newPasswordString = String(cString: newPassword)

let query: [String: Any] = [
kSecClass as String: kSecClassGenericPassword,
kSecAttrService as String: serviceString,
kSecAttrAccount as String: accountString
]

let updateFields: [String: Any] = [
kSecValueData as String: newPasswordString.data(using: .utf8)!
]

let status = SecItemUpdate(query as CFDictionary, updateFields as CFDictionary)

return status == errSecSuccess
}

@_cdecl("deletePassword")
public func deletePassword(service: UnsafePointer<CChar>, account: UnsafePointer<CChar>) -> Bool {
let serviceString = String(cString: service)
let accountString = String(cString: account)

let query: [String: Any] = [
kSecClass as String: kSecClassGenericPassword,
kSecAttrService as String: serviceString,
kSecAttrAccount as String: accountString
]

let status = SecItemDelete(query as CFDictionary)

return status == errSecSuccess
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package com.clipevery.macos

import com.clipevery.platform.currentPlatform
import org.junit.Test
import kotlin.test.assertEquals
import kotlin.test.assertTrue

class MacosKeychainHelperTest {

@Test
fun testKeychain() {
if (currentPlatform().isMacos()) {
MacosKeychainHelper.setPassword("com.clipevery", "test", "test")
var password = MacosKeychainHelper.getPassword("com.clipevery", "test")
assertEquals("test", password)
MacosKeychainHelper.updatePassword("com.clipevery", "test", "test1")
password = MacosKeychainHelper.getPassword("com.clipevery", "test")
assertEquals("test1", password)
assertTrue(MacosKeychainHelper.deletePassword("com.clipevery", "test"))
val password1 = MacosKeychainHelper.getPassword("com.clipevery", "test")
assertTrue(password1 == null)
}
}
}

0 comments on commit 95070bf

Please sign in to comment.