🤞 One failure left...

This commit is contained in:
Netscape Navigator 2020-04-18 09:59:56 -05:00
parent 68c4c45427
commit 49a3623b28
5 changed files with 53 additions and 47 deletions

28
dist/pigeon.rb vendored
View File

@ -60,6 +60,12 @@ module Pigeon
# /Constants for internal use only
class Helpers
VERFIY_ERROR = "Expected field `%s` to equal %s, got: %s"
MSG_SIZE_ERROR = "Messages cannot have more than 64 keys. Got %s."
class VerificationError < StandardError; end
class MessageSizeError < StandardError; end
B32_ENC = {
"00000" => "0", "00001" => "1", "00010" => "2", "00011" => "3",
"00100" => "4", "00101" => "5", "00110" => "6", "00111" => "7",
@ -145,7 +151,7 @@ module Pigeon
verify_key.verify(binary_signature, string)
end
def assert(field, actual, expected)
def self.assert(field, actual, expected)
unless actual == expected
message = VERFIY_ERROR % [field, actual || "nil", expected || "nil"]
raise VerificationError, message
@ -171,24 +177,30 @@ module Pigeon
message
end
def publish_message(db, msg)
return db.read_message(multihash) if db.message?(multihash)
def self.verify_message(db, msg)
msg_hash = msg.multihash
body = msg.body
key_count = body.count
author = msg.author
signature = msg.signature
return db.read_message(msg_hash) if db.message?(msg_hash)
if key_count > 64
msg = MSG_SIZE_ERROR % key_count
raise MessageSizeError, msg
end
count = db.get_message_count_for(author.multihash)
expected_prev = db.get_message_by_depth(author.multihash, count - 1) || Pigeon::NOTHING
assert("depth", count, depth)
assert("depth", count, msg.depth)
# TODO: Re-visit this. Our current verification method
# is probably too strict and won't allow for partial
# verification of feeds.
assert("lipmaa", Helpers.lipmaa(depth), lipmaa)
assert("prev", prev, expected_prev)
verify_signature
assert("lipmaa", Helpers.lipmaa(msg.depth), msg.lipmaa)
assert("prev", msg.prev, expected_prev)
tpl = msg.template.render_without_signature
Helpers.verify_string(author, signature, tpl)
msg.freeze
db.save_message(msg)
msg
end

View File

@ -21,7 +21,11 @@ module Pigeon
def all_peers(); store.all_peers(); end
def all_blocks(); store.all_blocks(); end
def message?(multihash); store.message?(multihash); end
def save_message(msg_obj); store.save_message(msg_obj); end
def save_message(msg_obj)
store.insert_message(Helpers.verify_message(self, msg_obj))
end
def read_message(multihash); store.read_message(multihash); end
def get_message_count_for(multihash)
@ -84,13 +88,14 @@ module Pigeon
# Store a message that someone (not the LocalIdentity)
# has authored.
def ingest(author:, body:, depth:, kind:, lipmaa:, prev:, signature:)
self.save_message(Message.new(author: RemoteIdentity.new(author),
kind: kind,
body: body,
prev: prev,
lipmaa: lipmaa,
signature: signature,
depth: depth))
msg = Message.new(author: RemoteIdentity.new(author),
kind: kind,
body: body,
prev: prev,
lipmaa: lipmaa,
signature: signature,
depth: depth)
save_message(msg)
end
private
@ -98,7 +103,7 @@ module Pigeon
attr_reader :store
def init_local_identity(new_seed)
key = store.get_config(SEED_CONFIG_KEY)
key = get_config(SEED_CONFIG_KEY)
if key
@local_identity = LocalIdentity.new(key)
else

View File

@ -4,12 +4,6 @@ module Pigeon
class Message
attr_reader :author, :kind, :body, :signature, :depth, :lipmaa, :prev
class VerificationError < StandardError; end
class MessageSizeError < StandardError; end
VERFIY_ERROR = "Expected field `%s` to equal %s, got: %s"
MSG_SIZE_ERROR = "Messages cannot have more than 64 keys. Got %s."
def render
template.render.chomp
end
@ -21,13 +15,6 @@ module Pigeon
"#{MESSAGE_SIGIL}#{sha256}#{BLOB_FOOTER}"
end
private
def verify_signature
tpl = template.render_without_signature
Helpers.verify_string(author, signature, tpl)
end
def initialize(author:,
kind:,
body:,

View File

@ -100,7 +100,7 @@ module Pigeon
read { store[MESG_NS].fetch(multihash) }
end
def save_message(msg)
def insert_message(msg)
write do
return msg if store[MESG_NS][msg.multihash]
insert_and_update_index(msg)

View File

@ -31,12 +31,12 @@ RSpec.describe Pigeon::Message do
it "discards a draft after signing" do
db.publish_draft(draft)
expect { db.current_draft }.to raise_error("NO DRAFT FOUND")
expect(db.current_draft).to be(nil)
end
it "creates a single message" do
message = db.publish_draft(draft)
expect(message.author.multihash).to eq(Pigeon::LocalIdentity.current.multihash)
expect(message.author.multihash).to eq(db.local_identity.multihash)
expect(message.body).to eq(draft.body)
expect(message.depth).to eq(0)
expect(message.kind).to eq("unit_test")
@ -100,7 +100,7 @@ RSpec.describe Pigeon::Message do
end
expect do
create_message(body)
end.to raise_error(Pigeon::Message::MessageSizeError, error)
end.to raise_error(Pigeon::Helpers::MessageSizeError, error)
end
it "verifies accuracy of signatures" do
@ -110,7 +110,7 @@ RSpec.describe Pigeon::Message do
plaintext = template.render_without_signature
# Make fake pairs of data for cross-checking
key1 = Pigeon::LocalIdentity.current.instance_variable_get(:@signing_key)
key1 = db.local_identity.instance_variable_get(:@signing_key)
key2 = Ed25519::SigningKey.new(secret)
sig1 = key1.sign(plaintext)
@ -128,20 +128,22 @@ RSpec.describe Pigeon::Message do
end
it "crashes on forged fields" do
tokens = [
[:AUTHOR, "@DYdgK1KUInVtG3lS45hA1HZ-jTuvfLKsxDpXPFCve04=.ed25519"],
[:KIND, "invalid"],
[:PREV, "NONE"],
[:DEPTH, 10],
[:LIPMAA, Pigeon::Helpers.lipmaa(10)],
[:HEADER_END],
[:BODY_ENTRY, "duplicate", "This key is a duplicate."],
[:SIGNATURE, "DN7yPTE-m433ND3jBL4oM23XGxBKafjq0Dp9ArBQa_TIGU7DmCxTumieuPBN-NKxlx_0N7-c5zjLb5XXVHYPCQ==.sig.ed25519"],
[:MESSAGE_END],
]
e = Pigeon::Helpers::VerificationError
m = "Expected field `depth` to equal 0, got: 10"
expect do
Pigeon::Parser.parse(db, [
[:AUTHOR, "@DYdgK1KUInVtG3lS45hA1HZ-jTuvfLKsxDpXPFCve04=.ed25519"],
[:KIND, "invalid"],
[:PREV, "NONE"],
[:DEPTH, 10],
[:LIPMAA, Pigeon::Helpers.lipmaa(10)],
[:HEADER_END],
[:BODY_ENTRY, "duplicate", "This key is a duplicate."],
[:SIGNATURE, "DN7yPTE-m433ND3jBL4oM23XGxBKafjq0Dp9ArBQa_TIGU7DmCxTumieuPBN-NKxlx_0N7-c5zjLb5XXVHYPCQ==.sig.ed25519"],
[:MESSAGE_END],
]).first.save!
end.to raise_error(Pigeon::Message::VerificationError, m)
msg = Pigeon::Parser.parse(db, tokens)[0]
end.to raise_error(e, m)
end
# Every ASCII character that is not a letter: