Coo... coo...
This commit is contained in:
commit
5ae1a0a943
|
@ -0,0 +1,2 @@
|
|||
coverage/
|
||||
.pigeon/
|
|
@ -0,0 +1,12 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
source "https://rubygems.org"
|
||||
|
||||
gem "ed25519"
|
||||
gem "thor"
|
||||
|
||||
group :dev do
|
||||
gem "rspec"
|
||||
gem "pry"
|
||||
gem "simplecov"
|
||||
end
|
|
@ -0,0 +1,44 @@
|
|||
GEM
|
||||
remote: https://rubygems.org/
|
||||
specs:
|
||||
coderay (1.1.2)
|
||||
diff-lcs (1.3)
|
||||
docile (1.3.2)
|
||||
ed25519 (1.2.4)
|
||||
json (2.2.0)
|
||||
method_source (0.9.2)
|
||||
pry (0.12.2)
|
||||
coderay (~> 1.1.0)
|
||||
method_source (~> 0.9.0)
|
||||
rspec (3.8.0)
|
||||
rspec-core (~> 3.8.0)
|
||||
rspec-expectations (~> 3.8.0)
|
||||
rspec-mocks (~> 3.8.0)
|
||||
rspec-core (3.8.2)
|
||||
rspec-support (~> 3.8.0)
|
||||
rspec-expectations (3.8.4)
|
||||
diff-lcs (>= 1.2.0, < 2.0)
|
||||
rspec-support (~> 3.8.0)
|
||||
rspec-mocks (3.8.1)
|
||||
diff-lcs (>= 1.2.0, < 2.0)
|
||||
rspec-support (~> 3.8.0)
|
||||
rspec-support (3.8.2)
|
||||
simplecov (0.17.1)
|
||||
docile (~> 1.1)
|
||||
json (>= 1.8, < 3)
|
||||
simplecov-html (~> 0.10.0)
|
||||
simplecov-html (0.10.2)
|
||||
thor (0.20.3)
|
||||
|
||||
PLATFORMS
|
||||
ruby
|
||||
|
||||
DEPENDENCIES
|
||||
ed25519
|
||||
pry
|
||||
rspec
|
||||
simplecov
|
||||
thor
|
||||
|
||||
BUNDLED WITH
|
||||
2.0.2
|
|
@ -0,0 +1,35 @@
|
|||
# Pigeon Ruby
|
||||
|
||||
A WIP pigeon protocol client.
|
||||
|
||||
# How to Use
|
||||
|
||||
This is a pre-release skeleton project. There is no gem yet. The gem will be released after we are fully compliant with the spec and have high test coverage stats.
|
||||
|
||||
To get started, clone this repo and run `./pigeon-cli` in place of `pigeon`.
|
||||
|
||||
Eg: `pigeon identity show` becomes `./pigeon-cli show`.
|
||||
|
||||
# Current Status
|
||||
|
||||
- [X] pigeon status
|
||||
- [X] pigeon identity new
|
||||
- [X] pigeon identity show
|
||||
|
||||
- [ ] pigeon blob set
|
||||
- [ ] pigeon blob get
|
||||
|
||||
- [ ] pigeon message new
|
||||
- [ ] pigeon message current
|
||||
- [ ] pigeon message append
|
||||
- [ ] pigeon message save
|
||||
- [ ] pigeon message find
|
||||
- [ ] pigeon message find-all
|
||||
|
||||
- [ ] pigeon peer add
|
||||
- [ ] pigeon peer remove
|
||||
- [ ] pigeon peer block
|
||||
- [ ] pigeon peer all
|
||||
|
||||
- [ ] pigeon bundle create
|
||||
- [ ] pigeon bundle consume
|
|
@ -0,0 +1,100 @@
|
|||
I need to implement these.
|
||||
|
||||
I'm adding them here for quick reference.
|
||||
|
||||
```bash
|
||||
pigeon status
|
||||
# => BLOBS: 10,234
|
||||
# => PEERS: 26
|
||||
# => VERSION: 0.0.1
|
||||
# => FOO: BAR
|
||||
|
||||
pigeon identity new
|
||||
# => @ajgdylxeifojlxpbmen3exlnsbx8buspsjh37b/ipvi=.ed25519
|
||||
|
||||
pigeon identity show
|
||||
# => @ajgdylxeifojlxpbmen3exlnsbx8buspsjh37b/ipvi=.ed25519
|
||||
|
||||
pigeon blob set '"Lol, data"'
|
||||
# => &2e7a0bc31f3c4fe6114051c3a56c8ed8a030b3b394df7d29d37648e9b8cbf54b.sha256
|
||||
|
||||
# Or use echo for big files:
|
||||
echo "Lol, data"' > pigeon blob set
|
||||
# => &2e7a0bc31f3c4fe6114051c3a56c8ed8a030b3b394df7d29d37648e9b8cbf54b.sha256
|
||||
|
||||
|
||||
pigeon blob get "&2e7a0bc31f3c4fe6114051c3a56c8ed8a030b3b394df7d29d37648e9b8cbf54b.sha256"
|
||||
# => "Lol, data"
|
||||
|
||||
pigeon message new my_message
|
||||
# => "Switched to message `my_message`
|
||||
|
||||
pigeon message current # Show active log entry.
|
||||
# => author: @ajgdylxeifojlxpbmen3exlnsbx8buspsjh37b/ipvi=.ed25519
|
||||
# => depth: 1
|
||||
# => kind: &82244417f956ac7c599f191593f7e441a4fafa20a4158fd52e154f1dc4c8ed92.sha256
|
||||
# => prev: %jvKh9yoiEJaePzoWCF1nnqpIlPgTk9FHEtqczQbvzGM=.sha256
|
||||
# =>
|
||||
# =>
|
||||
|
||||
pigeon message append --name=2e7a0bc3 --value=2e7a0bc3
|
||||
# => \n
|
||||
# => This needs to be cleaner.
|
||||
# => No one likes the way it is right now.
|
||||
# => We will come back to this monstrosity later.
|
||||
|
||||
pigeon message save
|
||||
# => author: @ajgdylxeifojlxpbmen3exlnsbx8buspsjh37b/ipvi=.ed25519
|
||||
# => depth: 1
|
||||
# => kind: &82244417f956ac7c599f191593f7e441a4fafa20a4158fd52e154f1dc4c8ed92.sha256
|
||||
# => prev: %jvKh9yoiEJaePzoWCF1nnqpIlPgTk9FHEtqczQbvzGM=.sha256
|
||||
# =>
|
||||
# => &ca978112ca1bbdcafac231b39a23dc4da786eff8147c4e72b9807785afee48bb.sha256:&2e7a0bc31f3c4fe6114051c3a56c8ed8a030b3b394df7d29d37648e9b8cbf54b.sha256
|
||||
# =>
|
||||
|
||||
pigeon message find %g0Fs9yoiEJaePzoWCF1nnqpIlPgTk9FHEtqczQbvzGM=.sha256
|
||||
# => author: @ajgdylxeifojlxpbmen3exlnsbx8buspsjh37b/ipvi=.ed25519
|
||||
# => depth: 1
|
||||
# => kind: &82244417f956ac7c599f191593f7e441a4fafa20a4158fd52e154f1dc4c8ed92.sha256
|
||||
# => prev: %jvKh9yoiEJaePzoWCF1nnqpIlPgTk9FHEtqczQbvzGM=.sha256
|
||||
# =>
|
||||
# => &ca978112ca1bbdcafac231b39a23dc4da786eff8147c4e72b9807785afee48bb.sha256:&2e7a0bc31f3c4fe6114051c3a56c8ed8a030b3b394df7d29d37648e9b8cbf54b.sha256
|
||||
# =>
|
||||
|
||||
pigeon message find-all --author=@ajgdylxeifojlxpbmen3exlnsbx8buspsjh37b/ipvi=.ed25519 --since=1
|
||||
# => author: @ajgdylxeifojlxpbmen3exlnsbx8buspsjh37b/ipvi=.ed25519
|
||||
# => depth: 1
|
||||
# => kind: &82244417f956ac7c599f191593f7e441a4fafa20a4158fd52e154f1dc4c8ed92.sha256
|
||||
# => prev: %jvKh9yoiEJaePzoWCF1nnqpIlPgTk9FHEtqczQbvzGM=.sha256
|
||||
# =>
|
||||
# => &ca978112ca1bbdcafac231b39a23dc4da786eff8147c4e72b9807785afee48bb.sha256:&2e7a0bc31f3c4fe6114051c3a56c8ed8a030b3b394df7d29d37648e9b8cbf54b.sha256
|
||||
# =>
|
||||
# => author: @ajgdylxeifojlxpbmen3exlnsbx8buspsjh37b/ipvi=.ed25519
|
||||
# => depth: 2
|
||||
# => kind: &82244417f956ac7c599f191593f7e441a4fafa20a4158fd52e154f1dc4c8ed92.sha256
|
||||
# => prev: %jvKh9yoiEJaePzoWCF1nnqpIlPgTk9FHEtqczQbvzGM=.sha256
|
||||
# =>
|
||||
# => &ca978112ca1bbdcafac231b39a23dc4da786eff8147c4e72b9807785afee48bb.sha256:&2e7a0bc31f3c4fe6114051c3a56c8ed8a030b3b394df7d29d37648e9b8cbf54b.sha256
|
||||
# =>
|
||||
|
||||
pigeon peer add @m0LEP+0NrGqu1wT8/4a3nOPuRBM+DrMpUahDZ3/cDi8=.ed25519
|
||||
# =>
|
||||
|
||||
pigeon peer remove @78daXMc/BOq5F1RWLMN4zgPVBVLqA4ShkLgE6z9OUGQ=.ed25519
|
||||
# =>
|
||||
|
||||
pigeon peer block @GOl+398b2kWeLi6+DCcU0i3AWD6vWmUtocBVYbpkpNk=.ed25519
|
||||
# =>
|
||||
|
||||
pigeon peer all
|
||||
# => @c8hovH5OOzNJ1SXUsIN+zI23xMcvGdEbs3ZJgzpthrw=.ed25519
|
||||
# => @GOl+398b2kWeLi6+DCcU0i3AWD6vWmUtocBVYbpkpNk=.ed25519
|
||||
# => @m0LEP+0NrGqu1wT8/4a3nOPuRBM+DrMpUahDZ3/cDi8=.ed25519
|
||||
|
||||
pigeon bundle create
|
||||
# => (creates @GOl+398b2kWeLi6+DCcU0i3AWD6vWmUtocBVYbpkpNk=.ed25519.pigeon)
|
||||
|
||||
pigeon bundle consume @GOl+398b2kWeLi6+DCcU0i3AWD6vWmUtocBVYbpkpNk=.ed25519.pigeon
|
||||
# =>
|
||||
|
||||
```
|
|
@ -0,0 +1,6 @@
|
|||
require_relative File.join("pigeon", "config.rb")
|
||||
require_relative File.join("pigeon", "storage.rb")
|
||||
require_relative File.join("pigeon", "key_pair.rb")
|
||||
|
||||
module Pigeon
|
||||
end
|
|
@ -0,0 +1,6 @@
|
|||
|
||||
module Pigeon
|
||||
module Config
|
||||
VERSION = "0.0.1"
|
||||
end
|
||||
end
|
|
@ -0,0 +1,43 @@
|
|||
require "ed25519"
|
||||
require "securerandom"
|
||||
require "base64"
|
||||
|
||||
module Pigeon
|
||||
# This is a wrapper around the `ed25519` gem to
|
||||
# help us maintain our sanity when the Gem's API
|
||||
# changes.
|
||||
class KeyPair
|
||||
HEADER, FOOTER = ["@", ".ed25519"]
|
||||
|
||||
def self.current
|
||||
raise "TODO"
|
||||
end
|
||||
|
||||
# `seed` is a 32-byte seed value from which
|
||||
# the key should be derived
|
||||
def initialize(seed = SecureRandom.random_bytes(Ed25519::KEY_SIZE))
|
||||
@seed = seed
|
||||
@raw_key = Ed25519::SigningKey.new(seed)
|
||||
end
|
||||
|
||||
def private_key
|
||||
@private_key ||= Base64.strict_encode64(@seed)
|
||||
end
|
||||
|
||||
def public_key
|
||||
bytes = @raw_key.verify_key.to_bytes
|
||||
b64 = Base64.strict_encode64(bytes)
|
||||
|
||||
@public_key ||= [HEADER, b64, FOOTER].join("")
|
||||
end
|
||||
|
||||
def save!
|
||||
{
|
||||
public_key: public_key,
|
||||
private_key: private_key,
|
||||
}.map do |k, v|
|
||||
Pigeon::Storage.current.save_conf(k, v)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,75 @@
|
|||
require "pry"
|
||||
require "digest"
|
||||
|
||||
module Pigeon
|
||||
class Storage
|
||||
ROOT_DIR = ".pigeon"
|
||||
CONF_DIR = "conf"
|
||||
BLOB_DIR = "blobs"
|
||||
|
||||
def self.current
|
||||
@current ||= self.new
|
||||
end
|
||||
|
||||
def initialize
|
||||
unless initialized?
|
||||
create_root_dir
|
||||
create_conf_dir
|
||||
create_blob_dir
|
||||
end
|
||||
end
|
||||
|
||||
def save_conf(key, value)
|
||||
path = conf_path_for(key)
|
||||
File.write(path, value.to_s)
|
||||
end
|
||||
|
||||
def get_conf(key)
|
||||
File.read(conf_path_for(key))
|
||||
end
|
||||
|
||||
def set_blob(data)
|
||||
hash = Digest::SHA256.hexdigest(data)
|
||||
path = blob_path_for(hash)
|
||||
|
||||
File.write(path, data)
|
||||
end
|
||||
|
||||
def initialized?
|
||||
File.directory?(root_dir)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def blob_dir
|
||||
@blob_dir ||= File.join(ROOT_DIR, BLOB_DIR, "sha256")
|
||||
end
|
||||
|
||||
def root_dir
|
||||
@root_dir ||= File.join(ROOT_DIR)
|
||||
end
|
||||
|
||||
# WARNING: Side effects. Im in a hurry. -RC
|
||||
def blob_path_for(hex_hash_string)
|
||||
first_part = File.join(blob_dir, hex_hash_string[0, 2])
|
||||
FileUtils.mkdir_p(first_part)
|
||||
File.join(first_part, hex_hash_string[2..-1])
|
||||
end
|
||||
|
||||
def conf_path_for(key)
|
||||
File.join(conf_dir, key.to_s)
|
||||
end
|
||||
|
||||
def create_conf_dir
|
||||
FileUtils.mkdir_p(File.join(ROOT_DIR, CONF_DIR))
|
||||
end
|
||||
|
||||
def create_blob_dir
|
||||
FileUtils.mkdir_p(blob_dir)
|
||||
end
|
||||
|
||||
def create_root_dir
|
||||
FileUtils.mkdir_p(root_dir)
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,63 @@
|
|||
#!/usr/bin/env ruby
|
||||
|
||||
require_relative File.join("dist", "pigeon")
|
||||
|
||||
require "thor"
|
||||
|
||||
module Pigeon
|
||||
class Identity < Thor
|
||||
class RoostAlreadyExists < StandardError; end
|
||||
|
||||
desc "new", "Creates a new identiy in `.pigeon` directory if none exists"
|
||||
|
||||
def new
|
||||
# TODO: --force flag
|
||||
# TODO: --seed flag
|
||||
if Dir.exist?(Pigeon::Storage::ROOT_DIR)
|
||||
puts "Pigeon has detected a `.pigeon` directory.
|
||||
Refusing to overwrite existing Pigeon config.
|
||||
Remove roost or switch to a different directory."
|
||||
raise RoostAlreadyExists
|
||||
end
|
||||
kp = Pigeon::KeyPair.new()
|
||||
kp.save!
|
||||
puts kp.public_key
|
||||
end
|
||||
|
||||
desc "show", "Prints a base64 identiy string to STDOUT"
|
||||
|
||||
def show
|
||||
puts Pigeon::Storage.current.get_conf("public_key")
|
||||
end
|
||||
end
|
||||
|
||||
class Blob < Thor
|
||||
desc "set", "Copy arbitrary binary data into the roost"
|
||||
|
||||
def set(data)
|
||||
Pigeon::Storage.current.set_blob(data)
|
||||
end
|
||||
|
||||
desc "get", "Read arbitrary data from the roost"
|
||||
|
||||
def get
|
||||
raise "WIP"
|
||||
end
|
||||
end
|
||||
|
||||
class CLI < Thor
|
||||
desc "status", "Show various information about the `.pigeon` directory"
|
||||
|
||||
def status
|
||||
puts "Version: #{Config::VERSION}"
|
||||
end
|
||||
|
||||
desc "identity SUBCOMMAND ...ARGS", "Manage `.pigeon` identity"
|
||||
subcommand "identity", Identity
|
||||
|
||||
desc "blob SUBCOMMAND ...ARGS", "Manage blob storage"
|
||||
subcommand "blob", Blob
|
||||
end
|
||||
end
|
||||
|
||||
Pigeon::CLI.start(ARGV)
|
|
@ -0,0 +1,7 @@
|
|||
require "spec_helper"
|
||||
|
||||
RSpec.describe Pigeon::Config do
|
||||
it "has a `foo`" do
|
||||
expect(Pigeon::Config::VERSION).to eq("0.0.1")
|
||||
end
|
||||
end
|
|
@ -0,0 +1,19 @@
|
|||
require "spec_helper"
|
||||
|
||||
RSpec.describe Pigeon::KeyPair do
|
||||
FAKE_SEED = "\x15\xB1\xA8\x1D\xE1\x1Cx\xF0" \
|
||||
"\xC6\xDCK\xDE\x9A\xB7>\x86o\x92\xEF\xB7\x17" \
|
||||
")\xFF\x01E\b$b)\xC9\x82\b"
|
||||
|
||||
let(:kp) { Pigeon::KeyPair.new(FAKE_SEED) }
|
||||
|
||||
it "generates a pair from a seed" do
|
||||
x = "@7n/g0ca9FFWvMkXy2TMwM7bdMn6tNiEHKzrFX+CzAmQ=.ed25519"
|
||||
expect(kp.public_key).to eq(x)
|
||||
y = "FbGoHeEcePDG3Evemrc+hm+S77cXKf8BRQgkYinJggg="
|
||||
expect(kp.private_key).to eq(y)
|
||||
end
|
||||
|
||||
# TODO Add fakefs https://github.com/fakefs/fakefss
|
||||
it "saves keypairs to disk"
|
||||
end
|
|
@ -0,0 +1,9 @@
|
|||
require "pry"
|
||||
require "simplecov"
|
||||
SimpleCov.start
|
||||
require_relative File.join("..", "dist", "pigeon")
|
||||
# See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
|
||||
RSpec.configure do |config|
|
||||
config.disable_monkey_patching!
|
||||
config.order = :random
|
||||
end
|
Loading…
Reference in New Issue