Mute keywords

This commit is contained in:
Vitor Pamplona
2023-09-24 15:10:50 -04:00
parent 57dfe3af8c
commit f4da2ae6be
16 changed files with 843 additions and 74 deletions
@@ -16,6 +16,7 @@ class BookmarkListEvent(
content: String,
sig: HexKey
) : GeneralListEvent(id, pubKey, createdAt, kind, tags, content, sig) {
@Transient
var decryptedContent = ""
companion object {
@@ -125,14 +125,20 @@ open class Event(
override fun matchTag1With(text: String) = tags.any { it.size > 1 && it[1].contains(text, true) }
override fun isTaggedUser(idHex: String) = tags.any { it.size > 1 && it[0] == "p" && it[1] == idHex }
override fun isTaggedUsers(idHexes: Set<String>) = tags.any { it.size > 1 && it[0] == "p" && it[1] in idHexes }
override fun isTagged(key: String, tag: String) = tags.any { it.size > 1 && it[0] == key && it[1] == tag }
override fun isTaggedEvent(idHex: String) = tags.any { it.size > 1 && it[0] == "e" && it[1] == idHex }
override fun isAnyTagged(key: String, tags: Set<String>) = this.tags.any { it.size > 1 && it[0] == key && it[1] in tags }
override fun isTaggedAddressableNote(idHex: String) = tags.any { it.size > 1 && it[0] == "a" && it[1] == idHex }
override fun isTaggedWord(word: String) = isTagged("word", word)
override fun isTaggedAddressableNotes(idHexes: Set<String>) = tags.any { it.size > 1 && it[0] == "a" && it[1] in idHexes }
override fun isTaggedUser(idHex: String) = isTagged("p", idHex)
override fun isTaggedUsers(idHexes: Set<String>) = isAnyTagged("p", idHexes)
override fun isTaggedEvent(idHex: String) = isTagged("e", idHex)
override fun isTaggedAddressableNote(idHex: String) = isTagged("a", idHex)
override fun isTaggedAddressableNotes(idHexes: Set<String>) = isAnyTagged( "a", idHexes)
override fun isTaggedHash(hashtag: String) = tags.any { it.size > 1 && it[0] == "t" && it[1].equals(hashtag, true) }
@@ -29,6 +29,10 @@ interface EventInterface {
fun hasValidSignature(): Boolean
fun isTagged(key: String, tag: String): Boolean
fun isAnyTagged(key: String, tags: Set<String>): Boolean
fun isTaggedWord(word: String): Boolean
fun isTaggedUser(idHex: String): Boolean
fun isTaggedUsers(idHex: Set<String>): Boolean
@@ -66,7 +66,8 @@ abstract class GeneralListEvent(
return privateTagsCache
}
fun privateTagsOrEmpty(privKey: ByteArray): List<List<String>> {
fun privateTagsOrEmpty(privKey: ByteArray?): List<List<String>> {
if (privKey == null) return emptyList()
return privateTags(privKey) ?: emptyList()
}
@@ -18,62 +18,94 @@ class PeopleListEvent(
content: String,
sig: HexKey
) : GeneralListEvent(id, pubKey, createdAt, kind, tags, content, sig) {
@Transient
var decryptedContent: String? = null
@Transient
var publicAndPrivateUserCache: ImmutableSet<HexKey>? = null
@Transient
var publicAndPrivateWordCache: ImmutableSet<String>? = null
fun filterTagList(key: String, privateTags: List<List<String>>?): ImmutableSet<String> {
val privateUserList = privateTags?.let {
it.filter { it.size > 1 && it[0] == key }.map { it[1] }.toSet()
} ?: emptySet()
val publicUserList = tags.filter { it.size > 1 && it[0] == key }.map { it[1] }.toSet()
return (privateUserList + publicUserList).toImmutableSet()
}
fun publicAndPrivateWords(privateKey: ByteArray?): ImmutableSet<String> {
publicAndPrivateWordCache?.let {
return it
}
publicAndPrivateWordCache = filterTagList("word", privateTagsOrEmpty(privKey = privateKey))
return publicAndPrivateWordCache ?: persistentSetOf()
}
fun publicAndPrivateUsers(privateKey: ByteArray?): ImmutableSet<HexKey> {
publicAndPrivateUserCache?.let {
return it
}
val privateUserList = privateKey?.let {
privateTagsOrEmpty(privKey = it).filter { it.size > 1 && it[0] == "p" }.map { it[1] }.toSet()
} ?: emptySet()
val publicUserList = tags.filter { it.size > 1 && it[0] == "p" }.map { it[1] }.toSet()
publicAndPrivateUserCache = (privateUserList + publicUserList).toImmutableSet()
publicAndPrivateUserCache = filterTagList("p", privateTagsOrEmpty(privKey = privateKey))
return publicAndPrivateUserCache ?: persistentSetOf()
}
fun publicAndPrivateWords(decryptedContent: String): ImmutableSet<HexKey> {
publicAndPrivateWordCache?.let {
return it
}
publicAndPrivateWordCache = filterTagList("word", privateTagsOrEmpty(decryptedContent))
return publicAndPrivateWordCache ?: persistentSetOf()
}
fun publicAndPrivateUsers(decryptedContent: String): ImmutableSet<HexKey> {
publicAndPrivateUserCache?.let {
return it
}
val privateUserList = privateTagsOrEmpty(decryptedContent).filter { it.size > 1 && it[0] == "p" }.map { it[1] }.toSet()
val publicUserList = tags.filter { it.size > 1 && it[0] == "p" }.map { it[1] }.toSet()
publicAndPrivateUserCache = (privateUserList + publicUserList).toImmutableSet()
publicAndPrivateUserCache = filterTagList("p", privateTagsOrEmpty(decryptedContent))
return publicAndPrivateUserCache ?: persistentSetOf()
}
fun isTaggedUser(idHex: String, isPrivate: Boolean, privateKey: ByteArray): Boolean {
fun isTagged(key: String, tag: String, isPrivate: Boolean, privateKey: ByteArray): Boolean {
return if (isPrivate) {
privateTagsOrEmpty(privKey = privateKey).any { it.size > 1 && it[0] == "p" && it[1] == idHex }
privateTagsOrEmpty(privKey = privateKey).any { it.size > 1 && it[0] == key && it[1] == tag }
} else {
isTaggedUser(idHex)
isTagged(key, tag)
}
}
fun isTaggedUser(idHex: String, isPrivate: Boolean, content: String): Boolean {
fun isTagged(key: String, tag: String, isPrivate: Boolean, decryptedContent: String): Boolean {
return if (isPrivate) {
privateTagsOrEmpty(content).any { it.size > 1 && it[0] == "p" && it[1] == idHex }
privateTagsOrEmpty(decryptedContent).any { it.size > 1 && it[0] == key && it[1] == tag }
} else {
isTaggedUser(idHex)
isTagged(key, tag)
}
}
fun isTaggedWord(word: String, isPrivate: Boolean, privateKey: ByteArray) = isTagged( "word", word, isPrivate, privateKey)
fun isTaggedUser(idHex: String, isPrivate: Boolean, privateKey: ByteArray) = isTagged( "p", idHex, isPrivate, privateKey)
fun isTaggedUser(idHex: String, isPrivate: Boolean, decryptedContent: String) = isTagged( "p", idHex, isPrivate, decryptedContent)
fun isTaggedWord(idHex: String, isPrivate: Boolean, decryptedContent: String) = isTagged( "word", idHex, isPrivate, decryptedContent)
companion object {
const val kind = 30000
const val blockList = "mute"
fun createListWithUser(name: String, pubKeyHex: String, isPrivate: Boolean, privateKey: ByteArray, createdAt: Long = TimeUtils.now()): PeopleListEvent {
fun createListWithTag(name: String, key: String, tag: String, isPrivate: Boolean, privateKey: ByteArray, createdAt: Long = TimeUtils.now()): PeopleListEvent {
return if (isPrivate) {
create(
content = encryptTags(listOf(listOf("p", pubKeyHex)), privateKey),
content = encryptTags(listOf(listOf(key, tag)), privateKey),
tags = listOf(listOf("d", name)),
privateKey = privateKey,
createdAt = createdAt
@@ -81,13 +113,21 @@ class PeopleListEvent(
} else {
create(
content = "",
tags = listOf(listOf("d", name), listOf("p", pubKeyHex)),
tags = listOf(listOf("d", name), listOf(key, tag)),
privateKey = privateKey,
createdAt = createdAt
)
}
}
fun createListWithUser(name: String, pubKeyHex: String, isPrivate: Boolean, privateKey: ByteArray, createdAt: Long = TimeUtils.now()): PeopleListEvent {
return createListWithTag(name, "p", pubKeyHex, isPrivate, privateKey, createdAt)
}
fun createListWithWord(name: String, word: String, isPrivate: Boolean, privateKey: ByteArray, createdAt: Long = TimeUtils.now()): PeopleListEvent {
return createListWithTag(name, "word", word, isPrivate, privateKey, createdAt)
}
fun createListWithUser(name: String, pubKeyHex: String, isPrivate: Boolean, pubKey: HexKey, encryptedContent: String, createdAt: Long = TimeUtils.now()): PeopleListEvent {
return if (isPrivate) {
create(
@@ -106,6 +146,24 @@ class PeopleListEvent(
}
}
fun createListWithWord(name: String, word: String, isPrivate: Boolean, pubKey: HexKey, encryptedContent: String, createdAt: Long = TimeUtils.now()): PeopleListEvent {
return if (isPrivate) {
create(
content = encryptedContent,
tags = listOf(listOf("d", name)),
pubKey = pubKey,
createdAt = createdAt
)
} else {
create(
content = "",
tags = listOf(listOf("d", name), listOf("word", word)),
pubKey = pubKey,
createdAt = createdAt
)
}
}
fun addUsers(earlierVersion: PeopleListEvent, listPubKeyHex: List<String>, isPrivate: Boolean, privateKey: ByteArray, createdAt: Long = TimeUtils.now()): PeopleListEvent {
return if (isPrivate) {
create(
@@ -135,6 +193,24 @@ class PeopleListEvent(
}
}
fun addWord(earlierVersion: PeopleListEvent, word: String, isPrivate: Boolean, pubKey: HexKey, encryptedContent: String, createdAt: Long = TimeUtils.now()): PeopleListEvent {
return if (isPrivate) {
create(
content = encryptedContent,
tags = earlierVersion.tags,
pubKey = pubKey,
createdAt = createdAt
)
} else {
create(
content = earlierVersion.content,
tags = earlierVersion.tags.plus(element = listOf("word", word)),
pubKey = pubKey,
createdAt = createdAt
)
}
}
fun addUser(earlierVersion: PeopleListEvent, pubKeyHex: String, isPrivate: Boolean, pubKey: HexKey, encryptedContent: String, createdAt: Long = TimeUtils.now()): PeopleListEvent {
return if (isPrivate) {
create(
@@ -153,13 +229,40 @@ class PeopleListEvent(
}
}
fun removeTag(earlierVersion: PeopleListEvent, tag: String, isPrivate: Boolean, pubKey: HexKey, encryptedContent: String, createdAt: Long = TimeUtils.now()): PeopleListEvent {
return if (isPrivate) {
create(
content = encryptedContent,
tags = earlierVersion.tags,
pubKey = pubKey,
createdAt = createdAt
)
} else {
create(
content = earlierVersion.content,
tags = earlierVersion.tags.filter { it.size > 1 && it[1] != tag },
pubKey = pubKey,
createdAt = createdAt
)
}
}
fun addWord(earlierVersion: PeopleListEvent, word: String, isPrivate: Boolean, privateKey: ByteArray, createdAt: Long = TimeUtils.now()): PeopleListEvent {
return addTag(earlierVersion, "word", word, isPrivate, privateKey, createdAt)
}
fun addUser(earlierVersion: PeopleListEvent, pubKeyHex: String, isPrivate: Boolean, privateKey: ByteArray, createdAt: Long = TimeUtils.now()): PeopleListEvent {
if (earlierVersion.isTaggedUser(pubKeyHex, isPrivate, privateKey)) return earlierVersion
return addTag(earlierVersion, "p", pubKeyHex, isPrivate, privateKey, createdAt)
}
fun addTag(earlierVersion: PeopleListEvent, key: String, tag: String, isPrivate: Boolean, privateKey: ByteArray, createdAt: Long = TimeUtils.now()): PeopleListEvent {
if (earlierVersion.isTagged(key, tag, isPrivate, privateKey)) return earlierVersion
return if (isPrivate) {
create(
content = encryptTags(
privateTags = earlierVersion.privateTagsOrEmpty(privKey = privateKey).plus(element = listOf("p", pubKeyHex)),
privateTags = earlierVersion.privateTagsOrEmpty(privKey = privateKey).plus(element = listOf(key, tag)),
privateKey = privateKey
),
tags = earlierVersion.tags,
@@ -169,48 +272,38 @@ class PeopleListEvent(
} else {
create(
content = earlierVersion.content,
tags = earlierVersion.tags.plus(element = listOf("p", pubKeyHex)),
tags = earlierVersion.tags.plus(element = listOf(key, tag)),
privateKey = privateKey,
createdAt = createdAt
)
}
}
fun removeUser(earlierVersion: PeopleListEvent, pubKeyHex: String, isPrivate: Boolean, encryptedContent: String, pubKey: HexKey, createdAt: Long = TimeUtils.now()): PeopleListEvent {
return if (isPrivate) {
create(
content = encryptedContent,
tags = earlierVersion.tags.filter { it.size > 1 && it[1] != pubKeyHex },
pubKey = pubKey,
createdAt = createdAt
)
} else {
create(
content = earlierVersion.content,
tags = earlierVersion.tags.filter { it.size > 1 && it[1] != pubKeyHex },
pubKey = pubKey,
createdAt = createdAt
)
}
fun removeWord(earlierVersion: PeopleListEvent, word: String, isPrivate: Boolean, privateKey: ByteArray, createdAt: Long = TimeUtils.now()): PeopleListEvent {
return removeTag(earlierVersion, "word", word, isPrivate, privateKey, createdAt)
}
fun removeUser(earlierVersion: PeopleListEvent, pubKeyHex: String, isPrivate: Boolean, privateKey: ByteArray, createdAt: Long = TimeUtils.now()): PeopleListEvent {
if (!earlierVersion.isTaggedUser(pubKeyHex, isPrivate, privateKey)) return earlierVersion
return removeTag(earlierVersion, "p", pubKeyHex, isPrivate, privateKey, createdAt)
}
fun removeTag(earlierVersion: PeopleListEvent, key: String, tag: String, isPrivate: Boolean, privateKey: ByteArray, createdAt: Long = TimeUtils.now()): PeopleListEvent {
if (!earlierVersion.isTagged(key, tag, isPrivate, privateKey)) return earlierVersion
return if (isPrivate) {
create(
content = encryptTags(
privateTags = earlierVersion.privateTagsOrEmpty(privKey = privateKey).filter { it.size > 1 && it[1] != pubKeyHex },
privateTags = earlierVersion.privateTagsOrEmpty(privKey = privateKey).filter { it.size > 1 && !(it[0] == key && it[1] == tag) },
privateKey = privateKey
),
tags = earlierVersion.tags.filter { it.size > 1 && it[1] != pubKeyHex },
tags = earlierVersion.tags.filter { it.size > 1 && !(it[0] == key && it[1] == tag) },
privateKey = privateKey,
createdAt = createdAt
)
} else {
create(
content = earlierVersion.content,
tags = earlierVersion.tags.filter { it.size > 1 && it[1] != pubKeyHex },
tags = earlierVersion.tags.filter { it.size > 1 && !(it[0] == key && it[1] == tag) },
privateKey = privateKey,
createdAt = createdAt
)