ccs 3.0.0 → 3.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +10 -0
- data/README.md +13 -3
- data/exe/ccs +7 -1
- data/lib/ccs.rb +2 -0
- data/lib/ccs/commands/copy.rb +25 -2
- data/lib/ccs/decrypter.rb +15 -0
- data/lib/ccs/document.rb +31 -2
- data/lib/ccs/downloader.rb +18 -0
- data/lib/ccs/encrypter.rb +19 -0
- data/lib/ccs/uploader.rb +23 -3
- data/lib/ccs/version.rb +2 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ce4380f6f1c426727a7147117ba50c7dc21866ec766ecf01083846e5340d8d79
|
4
|
+
data.tar.gz: 162d1b0bebdcbec23a1bb72b2c82d7ad4b6994c4ab6fc4258d1ebeebe29c61b9
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 70e1cd7ac88384e75d62093429b4fa37a4b2aba6c6b3439e47c856653b2eac54c56b2e55d11281b2258ee0497a6e5008cc365b3f402ae3277e6612764af9e502
|
7
|
+
data.tar.gz: 8b580583449616952eedf65b13e7c893464cfb7fd3595ff2f238eaf933741211dad276df92d31008b54b7d0976ed727bc9a9471d109dc6d8697e3caa047e2f3c
|
data/CHANGELOG.md
CHANGED
data/README.md
CHANGED
@@ -6,9 +6,7 @@ Configuration control system
|
|
6
6
|
|
7
7
|
Add this line to your application's Gemfile:
|
8
8
|
|
9
|
-
|
10
|
-
gem 'ccs'
|
11
|
-
```
|
9
|
+
gem 'ccs'
|
12
10
|
|
13
11
|
And then execute:
|
14
12
|
|
@@ -27,6 +25,7 @@ Or install it yourself as:
|
|
27
25
|
--access-token
|
28
26
|
-p CCS_PASSPHRASE, CCS Passphrase
|
29
27
|
--passphrase
|
28
|
+
-f, --[no-]force Overwrite remote documents when uploading
|
30
29
|
|
31
30
|
|
32
31
|
## Example
|
@@ -45,6 +44,10 @@ Upload local file
|
|
45
44
|
|
46
45
|
ccs cp /local/path/to/file.yml ccs://workspace-name/0.1.0/path/to/file.yml
|
47
46
|
|
47
|
+
Upload local file, overwriting remote document if any'
|
48
|
+
|
49
|
+
ccs cp --force /local/path/to/file.yml ccs://workspace-name/0.1.0/path/to/file.yml
|
50
|
+
|
48
51
|
Upload content from STDIN
|
49
52
|
|
50
53
|
echo "{ a: 1 }" | ccs cp - ccs://workspace-name/0.1.0/path/to/file.yml
|
@@ -79,6 +82,13 @@ After checking out the repo, run `bin/setup` to install dependencies. Then, run
|
|
79
82
|
|
80
83
|
To install this gem onto your local machine, run `bin/rake install`. To release a new version, update the version number in `version.rb`, and then run `bin/rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
|
81
84
|
|
85
|
+
## Documentation
|
86
|
+
|
87
|
+
Documentation for the code should be written in YARD format. It can be generated locally into the `doc` directory by running
|
88
|
+
|
89
|
+
bundle exec yard
|
90
|
+
|
91
|
+
|
82
92
|
## Contributing
|
83
93
|
|
84
94
|
Bug reports and pull requests are welcome on GitHub at https://github.com/occson/ccs. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](http://contributor-covenant.org) code of conduct.
|
data/exe/ccs
CHANGED
@@ -42,6 +42,10 @@ when 'cp'
|
|
42
42
|
options['passphrase'] = v
|
43
43
|
end
|
44
44
|
|
45
|
+
option_parser.on('-f', '--[no-]force', 'Overwrite remote documents when uploading') do |v|
|
46
|
+
options['force'] = v
|
47
|
+
end
|
48
|
+
|
45
49
|
option_parser.separator ''
|
46
50
|
option_parser.separator 'Configure via environment variables:'
|
47
51
|
option_parser.separator ' CCS_ACCESS_TOKEN'
|
@@ -57,6 +61,8 @@ when 'cp'
|
|
57
61
|
option_parser.separator ' ccs cp ccs://workspace-name/0.1.0/path/to/file.yml /local/path/to/file.yml'
|
58
62
|
option_parser.separator ' Upload local file'
|
59
63
|
option_parser.separator ' ccs cp /local/path/to/file.yml ccs://workspace-name/0.1.0/path/to/file.yml'
|
64
|
+
option_parser.separator ' Upload local file, overwriting remote document if any'
|
65
|
+
option_parser.separator ' ccs cp --force /local/path/to/file.yml ccs://workspace-name/0.1.0/path/to/file.yml'
|
60
66
|
option_parser.separator ' Upload content from STDIN'
|
61
67
|
option_parser.separator ' echo "{ a: 1 }" | ccs cp - ccs://workspace-name/0.1.0/path/to/file.yml'
|
62
68
|
option_parser.separator ' cat /local/path/to/file.yml | ccs cp - ccs://workspace-name/0.1.0/path/to/file.yml'
|
@@ -77,7 +83,7 @@ when 'cp'
|
|
77
83
|
raise OptionParser::MissingArgument, 'source' unless arguments.fetch(0, nil)
|
78
84
|
raise OptionParser::MissingArgument, 'destination' unless arguments.fetch(1, nil)
|
79
85
|
|
80
|
-
exit(1) unless Ccs::Commands::Copy.new(arguments[0], arguments[1], options['access_token'], options['passphrase']).call
|
86
|
+
exit(1) unless Ccs::Commands::Copy.new(arguments[0], arguments[1], options['access_token'], options['passphrase'], force: options.fetch('force', false)).call
|
81
87
|
else
|
82
88
|
puts option_parser
|
83
89
|
exit(1)
|
data/lib/ccs.rb
CHANGED
data/lib/ccs/commands/copy.rb
CHANGED
@@ -2,14 +2,37 @@
|
|
2
2
|
|
3
3
|
module Ccs
|
4
4
|
module Commands
|
5
|
+
# The copy command, responsible for copying a target to a destination, performing encryption
|
6
|
+
# and decryption as necessary.
|
7
|
+
#
|
8
|
+
# The target and destinations can be:
|
9
|
+
#
|
10
|
+
# - STDIN/STDOUT: a `-` sign is interpreted as these standard streams
|
11
|
+
#
|
12
|
+
# - The Occson server: strings beginning with `ccs://` or `http(s)://` are interpreted as such
|
13
|
+
#
|
14
|
+
# - local files: everything not matching the previous descriptions is assumed to
|
15
|
+
# be a path on the local system
|
5
16
|
class Copy
|
6
|
-
|
17
|
+
# Builds an instance of the Copy command.
|
18
|
+
#
|
19
|
+
# @param source [String] `-` for STDIN, an URI or a local file path
|
20
|
+
# @param destination [String] `-` for STDOUT, an URI or a local file path
|
21
|
+
# @param access_token [String] Occson access token
|
22
|
+
# @param passphrase [String] Passphrase used for encryption of the document
|
23
|
+
# @param force [Boolean] Whether to overwrite target document in Occson, if any. Default `false`.
|
24
|
+
def initialize(source, destination, access_token, passphrase, force: false)
|
7
25
|
@source = source
|
8
26
|
@destination = destination
|
9
27
|
@access_token = access_token
|
10
28
|
@passphrase = passphrase
|
29
|
+
@force = force
|
11
30
|
end
|
12
31
|
|
32
|
+
# Performs a transfer between locations - an upload if `@source` is local or STDIN,
|
33
|
+
# a download if `@source` is an URI.
|
34
|
+
#
|
35
|
+
# No guarantees are made about the return values of this method.
|
13
36
|
def call
|
14
37
|
download? ? download : upload
|
15
38
|
end
|
@@ -29,7 +52,7 @@ module Ccs
|
|
29
52
|
|
30
53
|
def upload
|
31
54
|
content = @source.eql?('-') ? STDIN.read : File.read(@source)
|
32
|
-
Document.new(@destination, @access_token, @passphrase).upload(content)
|
55
|
+
Document.new(@destination, @access_token, @passphrase).upload(content, force: @force)
|
33
56
|
end
|
34
57
|
end
|
35
58
|
end
|
data/lib/ccs/decrypter.rb
CHANGED
@@ -1,12 +1,27 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module Ccs
|
4
|
+
# Handles client-side decryption for documents.
|
5
|
+
#
|
6
|
+
# The decrypter uses AES-256 in CBC mode internally. A salt is
|
7
|
+
# expected in bytes 8..15, with ciphertext occupying the
|
8
|
+
# further bytes.
|
4
9
|
class Decrypter
|
10
|
+
# Constructs a Decrypter instance with given passphrase and content.
|
11
|
+
#
|
12
|
+
# @example
|
13
|
+
# Ccs::Decrypter.new('the content passphrase', content)
|
14
|
+
#
|
15
|
+
# @param passphrase [String] Passphrase for content decryption
|
16
|
+
# @param content [String] Encrypted document content
|
5
17
|
def initialize(passphrase, content)
|
6
18
|
@passphrase = passphrase
|
7
19
|
@content = content
|
8
20
|
end
|
9
21
|
|
22
|
+
# Performs decryption, returning plaintext if passphrase matched.
|
23
|
+
#
|
24
|
+
# @return [String] Plaintext document content
|
10
25
|
def call
|
11
26
|
decryptor.pkcs5_keyivgen(@passphrase, ciphertext_salt, 1)
|
12
27
|
result = decryptor.update(encrypted)
|
data/lib/ccs/document.rb
CHANGED
@@ -1,17 +1,46 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module Ccs
|
4
|
+
# An abstraction for the Document concept. Simplifies building URLs,
|
5
|
+
# uploading and downloading contents. Abstracts away workspaces due to
|
6
|
+
# the use of access tokens in constructions.
|
4
7
|
class Document
|
8
|
+
# Constructs a Document instance from a given URI, access token and passphrase.
|
9
|
+
#
|
10
|
+
# @example
|
11
|
+
# uri = 'ccs://path/to/file.yml'
|
12
|
+
# access_token = 'f30b5450421362c9ca0b'
|
13
|
+
# passphrase = 'my document passphrase'
|
14
|
+
#
|
15
|
+
# Ccs::Document.new(uri, access_token, passphrase)
|
16
|
+
#
|
17
|
+
# @param uri [String] Document URI. Accepts `ccs://` as shorthand for Occson location.
|
18
|
+
# @param access_token [String] Occson access token.
|
19
|
+
# @param passphrase [String] Document passphrase, used in encryption and decryption.
|
5
20
|
def initialize(uri, access_token, passphrase)
|
6
21
|
@uri = build_uri(uri)
|
7
22
|
@access_token = access_token
|
8
23
|
@passphrase = passphrase
|
9
24
|
end
|
10
25
|
|
11
|
-
|
12
|
-
|
26
|
+
# Uploads the given plaintext `content` to target URI.
|
27
|
+
#
|
28
|
+
# @example
|
29
|
+
# document.upload('My example plaintext.')
|
30
|
+
#
|
31
|
+
# @param content [String] Plaintext to be encrypted and uploaded.
|
32
|
+
# @param force [Boolean] Whether to overwrite target document in Occson, if any. Default `false`.
|
33
|
+
def upload(content, force: false)
|
34
|
+
Uploader.new(@uri, content, @access_token, @passphrase, force: force).call
|
13
35
|
end
|
14
36
|
|
37
|
+
# Downloads the encrypted document at `@uri` and returns the plaintext
|
38
|
+
# contents (given that `@passphrase` matches).
|
39
|
+
#
|
40
|
+
# @example
|
41
|
+
# plaintext = document.download
|
42
|
+
#
|
43
|
+
# @return [String] Decrypted document contents
|
15
44
|
def download
|
16
45
|
Downloader.new(@uri, @access_token, @passphrase).call
|
17
46
|
end
|
data/lib/ccs/downloader.rb
CHANGED
@@ -1,13 +1,31 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module Ccs
|
4
|
+
# Downloads and decrypts the document at given URI with given access token.
|
5
|
+
# Decryption occurs using given passphrase.
|
4
6
|
class Downloader
|
7
|
+
# Constructs a Downloader instance from a given URI, access token and passphrase.
|
8
|
+
#
|
9
|
+
# @example
|
10
|
+
# uri = 'ccs://path/to/file.yml'
|
11
|
+
# access_token = 'f30b5450421362c9ca0b'
|
12
|
+
# passphrase = 'my document passphrase'
|
13
|
+
#
|
14
|
+
# Ccs::Downloader.new(uri, access_token, passphrase)
|
15
|
+
#
|
16
|
+
# @param uri [String] Document URI. Accepts `ccs://` as shorthand for Occson location.
|
17
|
+
# @param access_token [String] Occson access token.
|
18
|
+
# @param passphrase [String] Document passphrase, used in encryption and decryption.
|
5
19
|
def initialize(uri, access_token, passphrase)
|
6
20
|
@uri = uri
|
7
21
|
@access_token = access_token
|
8
22
|
@passphrase = passphrase
|
9
23
|
end
|
10
24
|
|
25
|
+
# Performs the download and decryption of document.
|
26
|
+
#
|
27
|
+
# @return [String|nil] Decrypted body of the document or `nil` in case the
|
28
|
+
# server did not respond with a `200` HTTP code.
|
11
29
|
def call
|
12
30
|
response = http.request(request)
|
13
31
|
body = response.body
|
data/lib/ccs/encrypter.rb
CHANGED
@@ -1,13 +1,32 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module Ccs
|
4
|
+
# Encrypts the given content for transmission. Uses AES-256 in CBC
|
5
|
+
# mode internally, with salting.
|
4
6
|
class Encrypter
|
7
|
+
# Constructs an Encrypter instance with given passphrase, content and salt.
|
8
|
+
# Salt _must_ be exactly 8 characters long.
|
9
|
+
#
|
10
|
+
# @example
|
11
|
+
# passphrase = 'my long document passphrase'
|
12
|
+
# content = 'very secret content'
|
13
|
+
# salt = '12345678'
|
14
|
+
#
|
15
|
+
# Ccs::Encrypter.new(passphrase, content, salt)
|
16
|
+
#
|
17
|
+
# @param passphrase [String] Document passphrase.
|
18
|
+
# @param content [String] Plaintext content to be encrypted.
|
19
|
+
# @param salt [String] Salt to reinforce the encryption, included in
|
20
|
+
# plaintext in the encrypted document.
|
5
21
|
def initialize(passphrase, content, salt)
|
6
22
|
@passphrase = passphrase
|
7
23
|
@content = content
|
8
24
|
@salt = salt
|
9
25
|
end
|
10
26
|
|
27
|
+
# Performs the actual encryption, returning base64-encoded ciphertext.
|
28
|
+
#
|
29
|
+
# @return [String] base64-encoded ciphertext
|
11
30
|
def call
|
12
31
|
encryptor.pkcs5_keyivgen(@passphrase, @salt, 1)
|
13
32
|
encrypted = encryptor.update(@content)
|
data/lib/ccs/uploader.rb
CHANGED
@@ -1,17 +1,37 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module Ccs
|
4
|
+
# Encrypts and uploads the document to Occson.
|
4
5
|
class Uploader
|
5
|
-
|
6
|
+
# Constructs an Uploader instance from a given URI, content, access token and passphrase.
|
7
|
+
#
|
8
|
+
# @example
|
9
|
+
# uri = 'ccs://path/to/file.yml'
|
10
|
+
# content = 'my very secret message'
|
11
|
+
# access_token = 'f30b5450421362c9ca0b'
|
12
|
+
# passphrase = 'my document passphrase'
|
13
|
+
#
|
14
|
+
# Ccs::Uploader.new(uri, access_token, passphrase)
|
15
|
+
#
|
16
|
+
# @param uri [String] Document URI. Accepts `ccs://` as shorthand for Occson location.
|
17
|
+
# @param content [String] Plaintext for encryption and upload.
|
18
|
+
# @param access_token [String] Occson access token.
|
19
|
+
# @param passphrase [String] Document passphrase, used in encryption and decryption.
|
20
|
+
# @param force [Boolean] Whether to overwrite target document in Occson, if any. Default `false`.
|
21
|
+
def initialize(uri, content, access_token, passphrase, force: false)
|
6
22
|
@uri = uri
|
7
23
|
@content = content
|
8
24
|
@access_token = access_token
|
9
25
|
@passphrase = passphrase
|
26
|
+
@force = force.to_s
|
10
27
|
end
|
11
28
|
|
29
|
+
# Performs the actual upload to server.
|
30
|
+
#
|
31
|
+
# @return [Boolean] `true` for a successful upload, `false` otherwise
|
12
32
|
def call
|
13
|
-
request.body = { encrypted_content: encrypted_content }.to_json
|
14
|
-
http.request(request).code
|
33
|
+
request.body = { encrypted_content: encrypted_content, force: @force }.to_json
|
34
|
+
%w[200 201].include?(http.request(request).code)
|
15
35
|
end
|
16
36
|
|
17
37
|
private
|
data/lib/ccs/version.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ccs
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 3.
|
4
|
+
version: 3.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- tkowalewski
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: exe
|
11
11
|
cert_chain: []
|
12
|
-
date: 2020-
|
12
|
+
date: 2020-11-23 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: inch
|