chore: improve account

This commit is contained in:
hstyi
2025-06-24 16:56:06 +08:00
committed by hstyi
parent 1c8abf9cba
commit 01d0f9d4bd
8 changed files with 32 additions and 13 deletions

View File

@@ -42,7 +42,7 @@ class AccountManager private constructor() : ApplicationRunnerExtension {
fun getSecretKey() = account.secretKey fun getSecretKey() = account.secretKey
fun getPublicKey() = account.publicKey fun getPublicKey() = account.publicKey
fun getPrivateKey() = account.privateKey fun getPrivateKey() = account.privateKey
fun isSigned() = isFreePlan().not() && accountProperties.signed fun isSigned() = accountProperties.signed
fun isLocally() = account.isLocally fun isLocally() = account.isLocally
fun getLastSynchronizationOn() = accountProperties.lastSynchronizationOn fun getLastSynchronizationOn() = accountProperties.lastSynchronizationOn
fun getAccessToken() = account.accessToken fun getAccessToken() = account.accessToken

View File

@@ -97,7 +97,7 @@ class AccountOption : JPanel(BorderLayout()), OptionsPane.Option, Disposable {
planBox.add(Box.createHorizontalStrut(16)) planBox.add(Box.createHorizontalStrut(16))
val upgrade = JXHyperlink(object : AnAction(I18n.getString("termora.settings.account.upgrade")) { val upgrade = JXHyperlink(object : AnAction(I18n.getString("termora.settings.account.upgrade")) {
override fun actionPerformed(evt: AnActionEvent) { override fun actionPerformed(evt: AnActionEvent) {
Application.browse(URI.create("https://www.termora.app/pricing"))
} }
}) })
upgrade.isFocusable = false upgrade.isFocusable = false

View File

@@ -362,6 +362,7 @@ class LoginServerDialog(owner: Window) : DialogWrapper(owner) {
super.doOKAction() super.doOKAction()
} }
} catch (e: Exception) { } catch (e: Exception) {
if (log.isErrorEnabled) log.error(e.message, e)
withContext(Dispatchers.Swing) { withContext(Dispatchers.Swing) {
OptionPane.showMessageDialog( OptionPane.showMessageDialog(
this@LoginServerDialog, this@LoginServerDialog,

View File

@@ -117,13 +117,23 @@ class PushService private constructor() : SyncService(), Disposable, Application
} }
private fun push(data: Data) { private fun push(data: Data) {
val encryptedData = encryptData(data.id, data.data, data.ownerId)
if (encryptedData.isBlank()) {
if (log.isErrorEnabled) {
log.error("数据: {} 没有找到对应 ownerId 的密钥,此数据将标记为已同步", data.id)
}
// 标记为已经同步
updateData(data.id, synced = true)
return
}
val requestData = PushDataRequest( val requestData = PushDataRequest(
objectId = data.id, objectId = data.id,
ownerId = data.ownerId, ownerId = data.ownerId,
ownerType = data.ownerType, ownerType = data.ownerType,
version = data.version, version = data.version,
type = data.type, type = data.type,
data = encryptData(data.id, data.data), data = encryptedData,
) )
val request = Request.Builder().url("${accountManager.getServer()}/v1/data/push") val request = Request.Builder().url("${accountManager.getServer()}/v1/data/push")

View File

@@ -3,6 +3,7 @@ package app.termora.account
import app.termora.AES import app.termora.AES
import app.termora.database.* import app.termora.database.*
import app.termora.database.Data.Companion.toData import app.termora.database.Data.Companion.toData
import okhttp3.internal.EMPTY_BYTE_ARRAY
import org.apache.commons.codec.binary.Base64 import org.apache.commons.codec.binary.Base64
import org.apache.commons.codec.digest.DigestUtils import org.apache.commons.codec.digest.DigestUtils
import org.apache.commons.lang3.ObjectUtils import org.apache.commons.lang3.ObjectUtils
@@ -75,14 +76,21 @@ abstract class SyncService {
} }
} }
protected fun encryptData(id: String, data: String): String { protected fun encryptData(id: String, data: String, ownerId: String): String {
val iv = DigestUtils.sha256(id).copyOf(12) val iv = DigestUtils.sha256(id).copyOf(12)
return Base64.encodeBase64String( var secretKey = EMPTY_BYTE_ARRAY
AES.GCM.encrypt( if (ownerId != accountManager.getAccountId()) {
accountManager.getSecretKey(), iv, val team = accountManager.getTeams().firstOrNull { it.id == ownerId }
data.toByteArray() if (team == null) {
) return StringUtils.EMPTY
) } else {
secretKey = team.secretKey
}
} else if (ownerId == accountManager.getAccountId()) {
secretKey = accountManager.getSecretKey()
}
if (secretKey.isEmpty()) return StringUtils.EMPTY
return Base64.encodeBase64String(AES.GCM.encrypt(secretKey, iv, data.toByteArray()))
} }
protected fun decryptData(id: String, data: String): String { protected fun decryptData(id: String, data: String): String {

View File

@@ -50,7 +50,7 @@ class KeywordHighlightDialog(owner: Window) : DialogWrapper(owner) {
).apply { Disposer.register(disposable, this) } ).apply { Disposer.register(disposable, this) }
) )
if (accountManager.isSigned()) { if (accountManager.hasTeamFeature()) {
for (team in accountManager.getTeams()) { for (team in accountManager.getTeams()) {
tabbed.addTab( tabbed.addTab(
team.name, team.name,

View File

@@ -63,7 +63,7 @@ class KeyManagerDialog(
KeyManagerPanel(AccountOwner(accountManager.getAccountId(), accountManager.getEmail(), OwnerType.User)) KeyManagerPanel(AccountOwner(accountManager.getAccountId(), accountManager.getEmail(), OwnerType.User))
) )
if (accountManager.isSigned()) { if (accountManager.hasTeamFeature()) {
for (team in accountManager.getTeams()) { for (team in accountManager.getTeams()) {
tabbed.addTab( tabbed.addTab(
team.name, team.name,

View File

@@ -51,7 +51,7 @@ class TagDialog(owner: Window, private val accountOwnerId: String = StringUtils.
).apply { Disposer.register(disposable, this) } ).apply { Disposer.register(disposable, this) }
) )
if (accountManager.isSigned()) { if (accountManager.hasTeamFeature()) {
for (team in accountManager.getTeams()) { for (team in accountManager.getTeams()) {
tabbed.addTab( tabbed.addTab(
team.name, team.name,