🤞 One failure left...
This commit is contained in:
parent
68c4c45427
commit
49a3623b28
|
@ -60,6 +60,12 @@ module Pigeon
|
||||||
# /Constants for internal use only
|
# /Constants for internal use only
|
||||||
|
|
||||||
class Helpers
|
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 = {
|
B32_ENC = {
|
||||||
"00000" => "0", "00001" => "1", "00010" => "2", "00011" => "3",
|
"00000" => "0", "00001" => "1", "00010" => "2", "00011" => "3",
|
||||||
"00100" => "4", "00101" => "5", "00110" => "6", "00111" => "7",
|
"00100" => "4", "00101" => "5", "00110" => "6", "00111" => "7",
|
||||||
|
@ -145,7 +151,7 @@ module Pigeon
|
||||||
verify_key.verify(binary_signature, string)
|
verify_key.verify(binary_signature, string)
|
||||||
end
|
end
|
||||||
|
|
||||||
def assert(field, actual, expected)
|
def self.assert(field, actual, expected)
|
||||||
unless actual == expected
|
unless actual == expected
|
||||||
message = VERFIY_ERROR % [field, actual || "nil", expected || "nil"]
|
message = VERFIY_ERROR % [field, actual || "nil", expected || "nil"]
|
||||||
raise VerificationError, message
|
raise VerificationError, message
|
||||||
|
@ -171,24 +177,30 @@ module Pigeon
|
||||||
message
|
message
|
||||||
end
|
end
|
||||||
|
|
||||||
def publish_message(db, msg)
|
def self.verify_message(db, msg)
|
||||||
return db.read_message(multihash) if db.message?(multihash)
|
msg_hash = msg.multihash
|
||||||
|
body = msg.body
|
||||||
key_count = body.count
|
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
|
if key_count > 64
|
||||||
msg = MSG_SIZE_ERROR % key_count
|
msg = MSG_SIZE_ERROR % key_count
|
||||||
raise MessageSizeError, msg
|
raise MessageSizeError, msg
|
||||||
end
|
end
|
||||||
count = db.get_message_count_for(author.multihash)
|
count = db.get_message_count_for(author.multihash)
|
||||||
expected_prev = db.get_message_by_depth(author.multihash, count - 1) || Pigeon::NOTHING
|
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
|
# TODO: Re-visit this. Our current verification method
|
||||||
# is probably too strict and won't allow for partial
|
# is probably too strict and won't allow for partial
|
||||||
# verification of feeds.
|
# verification of feeds.
|
||||||
assert("lipmaa", Helpers.lipmaa(depth), lipmaa)
|
assert("lipmaa", Helpers.lipmaa(msg.depth), msg.lipmaa)
|
||||||
assert("prev", prev, expected_prev)
|
assert("prev", msg.prev, expected_prev)
|
||||||
verify_signature
|
tpl = msg.template.render_without_signature
|
||||||
|
Helpers.verify_string(author, signature, tpl)
|
||||||
msg.freeze
|
msg.freeze
|
||||||
db.save_message(msg)
|
|
||||||
msg
|
msg
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -21,7 +21,11 @@ module Pigeon
|
||||||
def all_peers(); store.all_peers(); end
|
def all_peers(); store.all_peers(); end
|
||||||
def all_blocks(); store.all_blocks(); end
|
def all_blocks(); store.all_blocks(); end
|
||||||
def message?(multihash); store.message?(multihash); 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 read_message(multihash); store.read_message(multihash); end
|
||||||
|
|
||||||
def get_message_count_for(multihash)
|
def get_message_count_for(multihash)
|
||||||
|
@ -84,13 +88,14 @@ module Pigeon
|
||||||
# Store a message that someone (not the LocalIdentity)
|
# Store a message that someone (not the LocalIdentity)
|
||||||
# has authored.
|
# has authored.
|
||||||
def ingest(author:, body:, depth:, kind:, lipmaa:, prev:, signature:)
|
def ingest(author:, body:, depth:, kind:, lipmaa:, prev:, signature:)
|
||||||
self.save_message(Message.new(author: RemoteIdentity.new(author),
|
msg = Message.new(author: RemoteIdentity.new(author),
|
||||||
kind: kind,
|
kind: kind,
|
||||||
body: body,
|
body: body,
|
||||||
prev: prev,
|
prev: prev,
|
||||||
lipmaa: lipmaa,
|
lipmaa: lipmaa,
|
||||||
signature: signature,
|
signature: signature,
|
||||||
depth: depth))
|
depth: depth)
|
||||||
|
save_message(msg)
|
||||||
end
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
@ -98,7 +103,7 @@ module Pigeon
|
||||||
attr_reader :store
|
attr_reader :store
|
||||||
|
|
||||||
def init_local_identity(new_seed)
|
def init_local_identity(new_seed)
|
||||||
key = store.get_config(SEED_CONFIG_KEY)
|
key = get_config(SEED_CONFIG_KEY)
|
||||||
if key
|
if key
|
||||||
@local_identity = LocalIdentity.new(key)
|
@local_identity = LocalIdentity.new(key)
|
||||||
else
|
else
|
||||||
|
|
|
@ -4,12 +4,6 @@ module Pigeon
|
||||||
class Message
|
class Message
|
||||||
attr_reader :author, :kind, :body, :signature, :depth, :lipmaa, :prev
|
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
|
def render
|
||||||
template.render.chomp
|
template.render.chomp
|
||||||
end
|
end
|
||||||
|
@ -21,13 +15,6 @@ module Pigeon
|
||||||
"#{MESSAGE_SIGIL}#{sha256}#{BLOB_FOOTER}"
|
"#{MESSAGE_SIGIL}#{sha256}#{BLOB_FOOTER}"
|
||||||
end
|
end
|
||||||
|
|
||||||
private
|
|
||||||
|
|
||||||
def verify_signature
|
|
||||||
tpl = template.render_without_signature
|
|
||||||
Helpers.verify_string(author, signature, tpl)
|
|
||||||
end
|
|
||||||
|
|
||||||
def initialize(author:,
|
def initialize(author:,
|
||||||
kind:,
|
kind:,
|
||||||
body:,
|
body:,
|
||||||
|
|
|
@ -100,7 +100,7 @@ module Pigeon
|
||||||
read { store[MESG_NS].fetch(multihash) }
|
read { store[MESG_NS].fetch(multihash) }
|
||||||
end
|
end
|
||||||
|
|
||||||
def save_message(msg)
|
def insert_message(msg)
|
||||||
write do
|
write do
|
||||||
return msg if store[MESG_NS][msg.multihash]
|
return msg if store[MESG_NS][msg.multihash]
|
||||||
insert_and_update_index(msg)
|
insert_and_update_index(msg)
|
||||||
|
|
|
@ -31,12 +31,12 @@ RSpec.describe Pigeon::Message do
|
||||||
|
|
||||||
it "discards a draft after signing" do
|
it "discards a draft after signing" do
|
||||||
db.publish_draft(draft)
|
db.publish_draft(draft)
|
||||||
expect { db.current_draft }.to raise_error("NO DRAFT FOUND")
|
expect(db.current_draft).to be(nil)
|
||||||
end
|
end
|
||||||
|
|
||||||
it "creates a single message" do
|
it "creates a single message" do
|
||||||
message = db.publish_draft(draft)
|
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.body).to eq(draft.body)
|
||||||
expect(message.depth).to eq(0)
|
expect(message.depth).to eq(0)
|
||||||
expect(message.kind).to eq("unit_test")
|
expect(message.kind).to eq("unit_test")
|
||||||
|
@ -100,7 +100,7 @@ RSpec.describe Pigeon::Message do
|
||||||
end
|
end
|
||||||
expect do
|
expect do
|
||||||
create_message(body)
|
create_message(body)
|
||||||
end.to raise_error(Pigeon::Message::MessageSizeError, error)
|
end.to raise_error(Pigeon::Helpers::MessageSizeError, error)
|
||||||
end
|
end
|
||||||
|
|
||||||
it "verifies accuracy of signatures" do
|
it "verifies accuracy of signatures" do
|
||||||
|
@ -110,7 +110,7 @@ RSpec.describe Pigeon::Message do
|
||||||
plaintext = template.render_without_signature
|
plaintext = template.render_without_signature
|
||||||
|
|
||||||
# Make fake pairs of data for cross-checking
|
# 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)
|
key2 = Ed25519::SigningKey.new(secret)
|
||||||
|
|
||||||
sig1 = key1.sign(plaintext)
|
sig1 = key1.sign(plaintext)
|
||||||
|
@ -128,20 +128,22 @@ RSpec.describe Pigeon::Message do
|
||||||
end
|
end
|
||||||
|
|
||||||
it "crashes on forged fields" do
|
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"
|
m = "Expected field `depth` to equal 0, got: 10"
|
||||||
expect do
|
expect do
|
||||||
Pigeon::Parser.parse(db, [
|
msg = Pigeon::Parser.parse(db, tokens)[0]
|
||||||
[:AUTHOR, "@DYdgK1KUInVtG3lS45hA1HZ-jTuvfLKsxDpXPFCve04=.ed25519"],
|
end.to raise_error(e, m)
|
||||||
[: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)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
# Every ASCII character that is not a letter:
|
# Every ASCII character that is not a letter:
|
||||||
|
|
Loading…
Reference in New Issue