README updates
This commit is contained in:
commit
d54b04bdaf
10
README.md
10
README.md
|
@ -50,7 +50,12 @@ Eg: `pigeon identity show` becomes `./pigeon-cli show`.
|
|||
- [X] Fix diagram in spec doc
|
||||
- [X] refactor `Bundle.create` to use `message find-all`.
|
||||
- [X] Rename `message find` to `message read`, since other finders return a multihash.
|
||||
<<<<<<< HEAD
|
||||
- [ ] Move stuff involving `LocalIdentity` out of `Message` class and into `Draft` class (re-use lexer logic)?
|
||||
=======
|
||||
- [ ] Message.ingest should be the only code path to message authoring.
|
||||
- [ ] Make all methods private except those required for the CLI.
|
||||
>>>>>>> draft_refactor
|
||||
- [ ] Don't allow any type of whitespace in `kind` or `string` keys. Write a test for this.
|
||||
- [ ] Add Lipmaa links like the Bamboo folks do.
|
||||
- [ ] Create regexes in ::Lexer using strings and Regexp.new() for cleaner regexes.
|
||||
|
@ -71,6 +76,11 @@ Eg: `pigeon identity show` becomes `./pigeon-cli show`.
|
|||
- [ ] Update spec document CLI usage examples to reflect API changes in 2020.
|
||||
- [ ] Performance benchmarks (Do this second to last!)
|
||||
- [ ] Performance tuning (Do this last!)
|
||||
- [ ] Set a max message size of 4k
|
||||
|
||||
# Do this later
|
||||
|
||||
- [ ] Interest and Disinterest Signalling for document routing: Create a `$gossip` message to express `blob.have`, `blob.want` and to note last message received of a peer. This can steer bundle creation and an eventual `--for` flag at bundle creation time.
|
||||
|
||||
# Idea Bin
|
||||
- [ ] Map/reduce plugin support for custom indices?
|
||||
|
|
|
@ -111,7 +111,7 @@ module Pigeon
|
|||
def self.create_message(kind, params)
|
||||
draft = Pigeon::Draft.create(kind: kind)
|
||||
params.map { |(k, v)| draft[k] = v }
|
||||
Pigeon::Message.publish(draft)
|
||||
draft.publish
|
||||
end
|
||||
|
||||
def self.verify_string(identity, string_signature, string)
|
||||
|
|
|
@ -2,7 +2,8 @@ require "digest"
|
|||
|
||||
module Pigeon
|
||||
class Draft
|
||||
attr_reader :kind, :body, :internal_id
|
||||
attr_reader :signature, :prev, :kind, :internal_id,
|
||||
:depth, :body, :author
|
||||
|
||||
def self.create(kind:, body: {})
|
||||
self.new(kind: kind, body: body).save
|
||||
|
@ -23,8 +24,12 @@ module Pigeon
|
|||
end
|
||||
|
||||
def initialize(kind:, body: {})
|
||||
@signature = Pigeon::EMPTY_MESSAGE
|
||||
@prev = Pigeon::EMPTY_MESSAGE
|
||||
@kind = kind
|
||||
@depth = -1
|
||||
@body = body
|
||||
@author = Pigeon::EMPTY_MESSAGE
|
||||
@internal_id = SecureRandom.uuid
|
||||
end
|
||||
|
||||
|
@ -49,12 +54,35 @@ module Pigeon
|
|||
end
|
||||
|
||||
def save
|
||||
puts "Rename to `save_as_draft` to avoid confusion"
|
||||
Pigeon::Storage.current.set_config(CURRENT_DRAFT, self)
|
||||
self
|
||||
end
|
||||
|
||||
# Author a new message.
|
||||
def publish
|
||||
template = MessageSerializer.new(self)
|
||||
|
||||
@author = LocalIdentity.current
|
||||
@depth = store.get_message_count_for(author.multihash)
|
||||
@prev = store.get_message_by_depth(author.multihash, @depth - 1)
|
||||
@signature = author.sign(template.render_without_signature)
|
||||
|
||||
candidate = template.render
|
||||
tokens = Lexer.tokenize(candidate)
|
||||
message = Parser.parse(tokens)[0]
|
||||
self.discard
|
||||
message
|
||||
end
|
||||
|
||||
def render
|
||||
puts "Rename to `render_as_draft` to avoid confusion."
|
||||
puts "Do we even need DraftSerializer any more?"
|
||||
DraftSerializer.new(self).render
|
||||
end
|
||||
|
||||
def store
|
||||
Pigeon::Storage.current
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -7,23 +7,6 @@ module Pigeon
|
|||
class VerificationError < StandardError; end
|
||||
|
||||
VERFIY_ERROR = "Expected field `%s` to equal %s, got: %s"
|
||||
# Author a new message.
|
||||
def self.publish(draft)
|
||||
author = LocalIdentity.current
|
||||
depth = Pigeon::Storage
|
||||
.current
|
||||
.get_message_count_for(author.multihash)
|
||||
count = store.get_message_count_for(author.multihash)
|
||||
prev = store.get_message_by_depth(author.multihash, count - 1)
|
||||
msg = self.new(author: author,
|
||||
kind: draft.kind,
|
||||
body: draft.body,
|
||||
depth: depth,
|
||||
prev: prev)
|
||||
msg.save!
|
||||
draft.discard
|
||||
msg
|
||||
end
|
||||
|
||||
# Store a message that someone (not the LocalIdentity)
|
||||
# has authored.
|
||||
|
@ -33,7 +16,7 @@ module Pigeon
|
|||
body: body,
|
||||
prev: prev,
|
||||
signature: signature,
|
||||
depth: depth)
|
||||
depth: depth).save!
|
||||
end
|
||||
|
||||
def render
|
||||
|
@ -41,13 +24,15 @@ module Pigeon
|
|||
end
|
||||
|
||||
def multihash
|
||||
sha256 = Helpers.b32_encode(Digest::SHA256.digest(self.render))
|
||||
tpl = self.render
|
||||
digest = Digest::SHA256.digest(tpl)
|
||||
sha256 = Helpers.b32_encode(digest)
|
||||
"#{MESSAGE_SIGIL}#{sha256}#{BLOB_FOOTER}"
|
||||
end
|
||||
|
||||
def save!
|
||||
puts "TODO: Make this method private."
|
||||
return store.read_message(multihash) if store.message?(multihash)
|
||||
calculate_signature
|
||||
verify_depth_prev_and_depth
|
||||
verify_signature
|
||||
self.freeze
|
||||
|
@ -86,22 +71,12 @@ module Pigeon
|
|||
@signature = signature
|
||||
end
|
||||
|
||||
def calculate_signature
|
||||
return if @signature
|
||||
#TODO: Verify that the author is Pigeon::LocalIdentity.current?
|
||||
@signature = author.sign(template.render_without_signature)
|
||||
end
|
||||
|
||||
def template
|
||||
MessageSerializer.new(self)
|
||||
end
|
||||
|
||||
def self.store
|
||||
Pigeon::Storage.current
|
||||
end
|
||||
|
||||
def store
|
||||
self.class.store
|
||||
Pigeon::Storage.current
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -108,7 +108,7 @@ RSpec.describe Pigeon::Lexer do
|
|||
let(:message) do
|
||||
draft = Pigeon::Draft.create(kind: "unit_test")
|
||||
draft["foo"] = "bar"
|
||||
Pigeon::Message.publish(draft)
|
||||
draft.publish
|
||||
end
|
||||
|
||||
before(:each) do
|
||||
|
|
|
@ -14,7 +14,7 @@ RSpec.describe Pigeon::Message do
|
|||
|
||||
def create_message(params)
|
||||
draft = create_draft(params)
|
||||
Pigeon::Message.publish(draft)
|
||||
draft.publish
|
||||
end
|
||||
|
||||
let(:draft) do
|
||||
|
@ -29,13 +29,13 @@ RSpec.describe Pigeon::Message do
|
|||
|
||||
it "discards a draft after signing" do
|
||||
expect(draft.internal_id).to eq(Pigeon::Draft.current.internal_id)
|
||||
Pigeon::Message.publish(draft)
|
||||
draft.publish
|
||||
expect { Pigeon::Draft.current }.to raise_error("NO DRAFT FOUND")
|
||||
end
|
||||
|
||||
it "creates a single message" do
|
||||
message = Pigeon::Message.publish(draft)
|
||||
expect(message.author).to eq(Pigeon::LocalIdentity.current)
|
||||
message = draft.publish
|
||||
expect(message.author.multihash).to eq(Pigeon::LocalIdentity.current.multihash)
|
||||
expect(message.body).to eq(draft.body)
|
||||
expect(message.depth).to eq(0)
|
||||
expect(message.kind).to eq("unit_test")
|
||||
|
@ -64,7 +64,7 @@ RSpec.describe Pigeon::Message do
|
|||
0.upto(4) do |expected_depth|
|
||||
draft1 = Pigeon::Draft.create(kind: "unit_test")
|
||||
draft1["description"] = "Message number #{expected_depth}"
|
||||
message = Pigeon::Message.publish(draft1)
|
||||
message = draft1.publish
|
||||
all.push(message)
|
||||
expect(message.depth).to eq(expected_depth)
|
||||
if expected_depth == 0
|
||||
|
@ -120,18 +120,19 @@ RSpec.describe Pigeon::Message do
|
|||
end
|
||||
|
||||
it "crashes on forged fields" do
|
||||
msg = Pigeon::Parser.parse([
|
||||
[:AUTHOR, "@DYdgK1KUInVtG3lS45hA1HZ-jTuvfLKsxDpXPFCve04=.ed25519"],
|
||||
[:KIND, "invalid"],
|
||||
[:PREV, "NONE"],
|
||||
[:DEPTH, 10],
|
||||
[:HEADER_END],
|
||||
[:BODY_ENTRY, "duplicate", "This key is a duplicate."],
|
||||
[:SIGNATURE, "DN7yPTE-m433ND3jBL4oM23XGxBKafjq0Dp9ArBQa_TIGU7DmCxTumieuPBN-NKxlx_0N7-c5zjLb5XXVHYPCQ==.sig.ed25519"],
|
||||
[:MESSAGE_END],
|
||||
])
|
||||
m = "Expected field `depth` to equal 0, got: 10"
|
||||
expect { msg.first.save! }.to raise_error(Pigeon::Message::VerificationError, m)
|
||||
expect do
|
||||
Pigeon::Parser.parse([
|
||||
[:AUTHOR, "@DYdgK1KUInVtG3lS45hA1HZ-jTuvfLKsxDpXPFCve04=.ed25519"],
|
||||
[:KIND, "invalid"],
|
||||
[:PREV, "NONE"],
|
||||
[:DEPTH, 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
|
||||
|
||||
# Every ASCII character that is not a letter:
|
||||
|
@ -143,8 +144,7 @@ RSpec.describe Pigeon::Message do
|
|||
kind[rand(0...8)] = n
|
||||
draft = Pigeon::Draft.create(kind: kind)
|
||||
draft["body"] = "empty"
|
||||
tpl = Pigeon::Message.publish(draft).render
|
||||
boom = ->() { Pigeon::Lexer.tokenize(tpl) }
|
||||
boom = ->() { Pigeon::Lexer.tokenize(draft.publish.render) }
|
||||
expect(boom).to raise_error(Pigeon::Lexer::LexError)
|
||||
end
|
||||
end
|
||||
|
@ -155,8 +155,7 @@ RSpec.describe Pigeon::Message do
|
|||
key = SecureRandom.alphanumeric(8)
|
||||
key[rand(0...8)] = n
|
||||
draft[key] = "should crash"
|
||||
tpl = Pigeon::Message.publish(draft).render
|
||||
boom = ->() { Pigeon::Lexer.tokenize(tpl) }
|
||||
boom = ->() { Pigeon::Lexer.tokenize(draft.publish.render) }
|
||||
expect(boom).to raise_error(Pigeon::Lexer::LexError)
|
||||
end
|
||||
end
|
||||
|
|
Loading…
Reference in New Issue