ndb: make NostrEvents immutable

Since we can't mutate NdbNotes, let's update the existing codebase to
generate and sign ids on NostrEvent constructions. This will allow us to
match NdbNote's constructor
This commit is contained in:
William Casarin
2023-07-25 08:58:06 -07:00
parent e3c04465fc
commit 2f8aa29e92
47 changed files with 2211 additions and 462 deletions

View File

@@ -40,15 +40,15 @@ class Contacts {
for d in diff {
if new.contains(d) {
new_mutes.append(d)
new_mutes.append(d.string())
} else {
new_unmutes.append(d)
new_unmutes.append(d.string())
}
}
// TODO: set local mutelist here
self.muted = Set(ev.referenced_pubkeys.map({ $0.ref_id }))
self.muted = Set(ev.referenced_pubkeys.map({ $0.ref_id.string() }))
if new_mutes.count > 0 {
notify(.new_mutes, new_mutes)
}
@@ -72,11 +72,7 @@ class Contacts {
func get_followed_hashtags() -> Set<String> {
guard let ev = self.event else { return Set() }
return ev.tags.reduce(into: Set<String>(), { htags, tag in
if tag.count >= 2 && tag[0] == "t" && tag[1] != "" {
htags.insert(tag[1])
}
})
return Set(ev.referenced_hashtags.map({ $0.ref_id.string() }))
}
func add_friend_pubkey(_ pubkey: String) {
@@ -85,18 +81,17 @@ class Contacts {
func add_friend_contact(_ contact: NostrEvent) {
friends.insert(contact.pubkey)
for tag in contact.tags {
if tag.count >= 2 && tag[0] == "p" {
friend_of_friends.insert(tag[1])
for tag in contact.referenced_pubkeys {
let pk = tag.id.string()
friend_of_friends.insert(pk)
// Exclude themself and us.
if contact.pubkey != our_pubkey && contact.pubkey != tag[1] {
if pubkey_to_our_friends[tag[1]] == nil {
pubkey_to_our_friends[tag[1]] = Set<String>()
}
pubkey_to_our_friends[tag[1]]?.insert(contact.pubkey)
// Exclude themself and us.
if contact.pubkey != our_pubkey && contact.pubkey != pk {
if pubkey_to_our_friends[pk] == nil {
pubkey_to_our_friends[pk] = Set<String>()
}
pubkey_to_our_friends[pk]?.insert(contact.pubkey)
}
}
}
@@ -128,13 +123,10 @@ class Contacts {
}
func follow_reference(box: PostBox, our_contacts: NostrEvent?, keypair: FullKeypair, follow: ReferencedId) -> NostrEvent? {
guard let ev = follow_user_event(our_contacts: our_contacts, our_pubkey: keypair.pubkey, follow: follow) else {
guard let ev = follow_user_event(our_contacts: our_contacts, keypair: keypair, follow: follow) else {
return nil
}
ev.calculate_id()
ev.sign(privkey: keypair.privkey)
box.send(ev)
return ev
@@ -145,28 +137,35 @@ func unfollow_reference(postbox: PostBox, our_contacts: NostrEvent?, keypair: Fu
return nil
}
let ev = unfollow_reference_event(our_contacts: cs, our_pubkey: keypair.pubkey, unfollow: unfollow)
ev.calculate_id()
ev.sign(privkey: keypair.privkey)
guard let ev = unfollow_reference_event(our_contacts: cs, keypair: keypair, unfollow: unfollow) else {
return nil
}
postbox.send(ev)
return ev
}
func unfollow_reference_event(our_contacts: NostrEvent, our_pubkey: String, unfollow: ReferencedId) -> NostrEvent {
func unfollow_reference_event(our_contacts: NostrEvent, keypair: FullKeypair, unfollow: ReferencedId) -> NostrEvent? {
let tags = our_contacts.tags.filter { tag in
if tag.count >= 2 && tag[0] == unfollow.key && tag[1] == unfollow.ref_id {
if let key = tag[safe: 0],
let ref = tag[safe: 1],
let fst = unfollow.key.first,
let afst = AsciiCharacter(fst),
key.matches_char(afst),
ref.string() == unfollow.ref_id
{
return false
}
return true
}
let kind = NostrKind.contacts.rawValue
return NostrEvent(content: our_contacts.content, pubkey: our_pubkey, kind: kind, tags: tags)
return NostrEvent(content: our_contacts.content, keypair: keypair.to_keypair(), kind: kind, tags: tags)
}
func follow_user_event(our_contacts: NostrEvent?, our_pubkey: String, follow: ReferencedId) -> NostrEvent? {
func follow_user_event(our_contacts: NostrEvent?, keypair: FullKeypair, follow: ReferencedId) -> NostrEvent? {
guard let cs = our_contacts else {
// don't create contacts for now so we don't nuke our contact list due to connectivity issues
// we should only create contacts during profile creation
@@ -174,7 +173,7 @@ func follow_user_event(our_contacts: NostrEvent?, our_pubkey: String, follow: Re
return nil
}
guard let ev = follow_with_existing_contacts(our_pubkey: our_pubkey, our_contacts: cs, follow: follow) else {
guard let ev = follow_with_existing_contacts(keypair: keypair, our_contacts: cs, follow: follow) else {
return nil
}
@@ -186,23 +185,18 @@ func decode_json_relays(_ content: String) -> [String: RelayInfo]? {
return decode_json(content)
}
func remove_relay(ev: NostrEvent, current_relays: [RelayDescriptor], privkey: String, relay: String) -> NostrEvent? {
func remove_relay(ev: NostrEvent, current_relays: [RelayDescriptor], keypair: FullKeypair, relay: String) -> NostrEvent?{
var relays = ensure_relay_info(relays: current_relays, content: ev.content)
relays.removeValue(forKey: relay)
print("remove_relay \(relays)")
guard let content = encode_json(relays) else {
return nil
}
let new_ev = NostrEvent(content: content, pubkey: ev.pubkey, kind: 3, tags: ev.tags)
new_ev.calculate_id()
new_ev.sign(privkey: privkey)
return new_ev
return NostrEvent(content: content, keypair: keypair.to_keypair(), kind: 3, tags: ev.tags)
}
func add_relay(ev: NostrEvent, privkey: String, current_relays: [RelayDescriptor], relay: String, info: RelayInfo) -> NostrEvent? {
func add_relay(ev: NostrEvent, keypair: FullKeypair, current_relays: [RelayDescriptor], relay: String, info: RelayInfo) -> NostrEvent? {
var relays = ensure_relay_info(relays: current_relays, content: ev.content)
guard relays.index(forKey: relay) == nil else {
@@ -215,10 +209,7 @@ func add_relay(ev: NostrEvent, privkey: String, current_relays: [RelayDescriptor
return nil
}
let new_ev = NostrEvent(content: content, pubkey: ev.pubkey, kind: 3, tags: ev.tags)
new_ev.calculate_id()
new_ev.sign(privkey: privkey)
return new_ev
return NostrEvent(content: content, keypair: keypair.to_keypair(), kind: 3, tags: ev.tags)
}
func ensure_relay_info(relays: [RelayDescriptor], content: String) -> [String: RelayInfo] {
@@ -229,19 +220,22 @@ func ensure_relay_info(relays: [RelayDescriptor], content: String) -> [String: R
}
func is_already_following(contacts: NostrEvent, follow: ReferencedId) -> Bool {
return contacts.references(id: follow.ref_id, key: follow.key)
guard let key = follow.key.first_char() else { return false }
return contacts.references(id: follow.ref_id, key: key)
}
func follow_with_existing_contacts(our_pubkey: String, our_contacts: NostrEvent, follow: ReferencedId) -> NostrEvent? {
func follow_with_existing_contacts(keypair: FullKeypair, our_contacts: NostrEvent, follow: ReferencedId) -> NostrEvent? {
// don't update if we're already following
if is_already_following(contacts: our_contacts, follow: follow) {
return nil
}
let kind = NostrKind.contacts.rawValue
var tags = our_contacts.tags
var tags = our_contacts.tags.strings()
tags.append(refid_to_tag(follow))
return NostrEvent(content: our_contacts.content, pubkey: our_pubkey, kind: kind, tags: tags)
return NostrEvent(content: our_contacts.content, keypair: keypair.to_keypair(), kind: kind, tags: tags)
}
func make_contact_relays(_ relays: [RelayDescriptor]) -> [String: RelayInfo] {

View File

@@ -821,10 +821,8 @@ func process_metadata_profile(our_pubkey: String, profiles: Profiles, profile: P
}
}
// TODO: remove this, let nostrdb handle all validation
func guard_valid_event(events: EventCache, ev: NostrEvent, callback: @escaping () -> Void) {
guard ev.id == hex_encode(calculate_event_id(ev: ev)) else {
return
}
let validated = events.is_event_valid(ev.id)
switch validated {

View File

@@ -473,14 +473,11 @@ func make_post_tags(post_blocks: [Block], tags: [[String]]) -> PostTags {
return PostTags(blocks: post_blocks, tags: new_tags)
}
func post_to_event(post: NostrPost, privkey: String, pubkey: String) -> NostrEvent {
func post_to_event(post: NostrPost, keypair: FullKeypair) -> NostrEvent? {
let tags = post.references.map(refid_to_tag) + post.tags
let post_blocks = parse_post_blocks(content: post.content)
let post_tags = make_post_tags(post_blocks: post_blocks, tags: tags)
let content = render_blocks(blocks: post_tags.blocks)
let new_ev = NostrEvent(content: content, pubkey: pubkey, kind: post.kind.rawValue, tags: post_tags.tags)
new_ev.calculate_id()
new_ev.sign(privkey: privkey)
return new_ev
return NostrEvent(content: content, keypair: keypair.to_keypair(), kind: post.kind.rawValue, tags: post_tags.tags)
}

View File

@@ -35,7 +35,7 @@ class ProfileModel: ObservableObject, Equatable {
}
for tag in contacts.tags {
guard tag.count >= 2 && tag[0] == "p" else {
guard tag.count >= 2 && tag[0].matches_char("p") else {
continue
}

View File

@@ -55,17 +55,8 @@ func create_report_tags(target: ReportTarget, type: ReportType) -> [[String]] {
}
}
func create_report_event(privkey: String, report: Report) -> NostrEvent? {
guard let pubkey = privkey_to_pubkey(privkey: privkey) else {
return nil
}
let kind = 1984
func create_report_event(keypair: FullKeypair, report: Report) -> NostrEvent? {
let kind: UInt32 = 1984
let tags = create_report_tags(target: report.target, type: report.type)
let ev = NostrEvent(content: report.message, pubkey: pubkey, kind: kind, tags: tags)
ev.id = hex_encode(calculate_event_id(ev: ev))
ev.sig = sign_event(privkey: privkey, ev: ev)
return ev
return NostrEvent(content: report.message, keypair: keypair.to_keypair(), kind: kind, tags: tags)
}