obfusc 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +12 -0
- data/.rspec +3 -0
- data/.travis.yml +5 -0
- data/Gemfile +8 -0
- data/Gemfile.lock +41 -0
- data/README.md +101 -0
- data/Rakefile +6 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/exe/obfusc +7 -0
- data/lib/obfusc/cli.rb +93 -0
- data/lib/obfusc/commands/concerns/config.rb +55 -0
- data/lib/obfusc/commands/concerns/encryptor_command_base.rb +73 -0
- data/lib/obfusc/commands/crypt_command.rb +38 -0
- data/lib/obfusc/commands/decrypt_command.rb +40 -0
- data/lib/obfusc/commands/setup_command.rb +61 -0
- data/lib/obfusc/commands/show_command.rb +49 -0
- data/lib/obfusc/config.rb +56 -0
- data/lib/obfusc/encryptor.rb +80 -0
- data/lib/obfusc/random.rb +31 -0
- data/lib/obfusc/version.rb +3 -0
- data/lib/obfusc.rb +19 -0
- data/obfusc.gemspec +28 -0
- metadata +111 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: a7fc494a9e84b4aaf03a3f8329f20ea56c75351f
|
4
|
+
data.tar.gz: a3b07cbc913a684a1fb3a03ef4c1a93bbad32768
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: da322a96246e4a6089df5015daa7573a9380e8676d3fd17f9c29876801f96ad1b1348b22648d7bfad095fb71ef0d408a1e3e556fde1ba9ef41cba67ccce6074b
|
7
|
+
data.tar.gz: f8d63efaab57384ff143e71f5c638c684c80b31836ad526d64aab2fe1d5ea5dae708407152384e819f340ef160b9692e63343cf93a04c1512e85d3d89439f09c
|
data/.gitignore
ADDED
data/.rspec
ADDED
data/.travis.yml
ADDED
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,41 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
obfusc (0.1.0)
|
5
|
+
|
6
|
+
GEM
|
7
|
+
remote: https://rubygems.org/
|
8
|
+
specs:
|
9
|
+
coderay (1.1.2)
|
10
|
+
diff-lcs (1.3)
|
11
|
+
method_source (0.9.0)
|
12
|
+
pry (0.11.3)
|
13
|
+
coderay (~> 1.1.0)
|
14
|
+
method_source (~> 0.9.0)
|
15
|
+
rake (10.5.0)
|
16
|
+
rspec (3.7.0)
|
17
|
+
rspec-core (~> 3.7.0)
|
18
|
+
rspec-expectations (~> 3.7.0)
|
19
|
+
rspec-mocks (~> 3.7.0)
|
20
|
+
rspec-core (3.7.1)
|
21
|
+
rspec-support (~> 3.7.0)
|
22
|
+
rspec-expectations (3.7.0)
|
23
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
24
|
+
rspec-support (~> 3.7.0)
|
25
|
+
rspec-mocks (3.7.0)
|
26
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
27
|
+
rspec-support (~> 3.7.0)
|
28
|
+
rspec-support (3.7.0)
|
29
|
+
|
30
|
+
PLATFORMS
|
31
|
+
ruby
|
32
|
+
|
33
|
+
DEPENDENCIES
|
34
|
+
bundler (~> 1.16)
|
35
|
+
obfusc!
|
36
|
+
pry (~> 0.11.3)
|
37
|
+
rake (~> 10.0)
|
38
|
+
rspec (~> 3.0)
|
39
|
+
|
40
|
+
BUNDLED WITH
|
41
|
+
1.16.0
|
data/README.md
ADDED
@@ -0,0 +1,101 @@
|
|
1
|
+
[![Build Status](https://img.shields.io/travis/marcosgz/obfusc.svg?style=flat)](https://travis-ci.org/marcosgz/obfusc)
|
2
|
+
|
3
|
+
# obfusc
|
4
|
+
Simple command line tool to obfuscate a recursive tree of files. Basically just rename a list of files using a random and reversible name. Probably no one will use it. It's something that I'd be interested in when I was a teenager and tried to hide inappropriate files on my PC.
|
5
|
+
|
6
|
+
*Always preferer "copy" command over "move". Unless you know exactly what are you doing.*
|
7
|
+
|
8
|
+
## Installation
|
9
|
+
Just install this gem by running
|
10
|
+
|
11
|
+
```
|
12
|
+
gem install obfusc
|
13
|
+
```
|
14
|
+
|
15
|
+
After successfully installed a new bin `obfusc` will be available.
|
16
|
+
|
17
|
+
## Configuration
|
18
|
+
First thing you will need to create a `$HOME/.obfusc.cnf` with with `secret` and `token` keys by executing the following command:
|
19
|
+
|
20
|
+
```
|
21
|
+
obfusct config generate
|
22
|
+
```
|
23
|
+
|
24
|
+
Here is an example of generated file:
|
25
|
+
```
|
26
|
+
$ cat ~/.obfusc.cnf
|
27
|
+
---
|
28
|
+
prefix: "obfusc"
|
29
|
+
suffix: "obfusc"
|
30
|
+
token: "@l(piZ3ynEz8tjs ,v7DUGP}SmrNMF:f=k4hbBc[dYWIo_uLJq|a9O]5gRK-T6AeXwQ);C{x1H02V"
|
31
|
+
secret: "-A:z0rH2Zc4Gb6L@;Cwyd3g)l7JRIa[x]hWsoUD_Epe5O}jifu QqM{89FT=SvVBn1t,|P(NmXKkY"
|
32
|
+
```
|
33
|
+
|
34
|
+
It's recommended to make a backup of this file before start using this script. All obfuscated depends on token and secret from this config file. All the obfuscated files can no longer be recovered if you overwrite `.obfusc.cnf`.
|
35
|
+
|
36
|
+
## Usage
|
37
|
+
|
38
|
+
Use `obfusc --help` to show basic usage and all commands available.
|
39
|
+
|
40
|
+
```
|
41
|
+
obfusc <command> <arguments> <options>
|
42
|
+
```
|
43
|
+
|
44
|
+
#### Commands
|
45
|
+
* setup
|
46
|
+
* crypt
|
47
|
+
* decrypt
|
48
|
+
|
49
|
+
#### Options
|
50
|
+
```
|
51
|
+
-c, --config FILENAME Using a different ".obfusc.cnf" filename (Default to $HOME/.obfusc.cnf)
|
52
|
+
-e, --extension STRING Specify a custom file extension. (Default to "obfc")
|
53
|
+
-p, --prefix STRING Specify a custom file prefix. (Default to "obfc")
|
54
|
+
-v, --[no-]verbose Run verbosely
|
55
|
+
-s, --[no-]simulate Do a simulate run without executing actions
|
56
|
+
```
|
57
|
+
|
58
|
+
### Crypt command
|
59
|
+
|
60
|
+
`crypt` is the command used to obfuscated one or more files. Should always be followed by `<move OR copy>` and `<source>` and an optional `<target>`.
|
61
|
+
|
62
|
+
Example:
|
63
|
+
```
|
64
|
+
# Simulate what will happen by executing this command
|
65
|
+
$ obfusc crypt copy -v -s empty.gif
|
66
|
+
DEBUG: cp empty.gif ./obfusc__6GP5D.nHv.obfusc
|
67
|
+
|
68
|
+
# Obfuscate the "empty.gif" file with the `copy` mode.
|
69
|
+
$ obfusc crypt copy empty.gif
|
70
|
+
|
71
|
+
# Show obfuscated file
|
72
|
+
$ obfusc show ./
|
73
|
+
./obfusc__6GP5D.nHv.obfusc:
|
74
|
+
---> empty.gif
|
75
|
+
|
76
|
+
# `copy` always keep the original file
|
77
|
+
$ ls empty.gif
|
78
|
+
empty.gif
|
79
|
+
```
|
80
|
+
|
81
|
+
### Decrypt command
|
82
|
+
`decrypt` is the command used to revert to original filename one or more obfuscated files. Should always be followed by `<move OR copy>` and `<source>` and an optional `<target>`.
|
83
|
+
|
84
|
+
Example:
|
85
|
+
```
|
86
|
+
# Simulate what will happen by executing this command
|
87
|
+
$ obfusc decrypt copy -s -v ./ /tmp/target
|
88
|
+
DEBUG: mkdir -p /tmp/target
|
89
|
+
DEBUG: cp ./obfusc__6GP5D.nHv.obfusc /tmp/target/empty.gif
|
90
|
+
|
91
|
+
# Rename obfuscated file to the original name and copy to the target directory
|
92
|
+
$ obfusc decrypt copy ./ /tmp/target
|
93
|
+
|
94
|
+
# Show un-obfuscated file
|
95
|
+
$ ls /tmp/target
|
96
|
+
empty.gif
|
97
|
+
|
98
|
+
# Original obfuscated file still existing with copy mode
|
99
|
+
$ ls ./obfusc__6GP5D.nHv.obfusc
|
100
|
+
./obfusc__6GP5D.nHv.obfusc
|
101
|
+
```
|
data/Rakefile
ADDED
data/bin/console
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require "bundler/setup"
|
4
|
+
require "obfusc"
|
5
|
+
|
6
|
+
# You can add fixtures and/or initialization code here to make experimenting
|
7
|
+
# with your gem easier. You can also use a different console, if you like.
|
8
|
+
|
9
|
+
# (If you use this, don't forget to add pry to your Gemfile!)
|
10
|
+
# require "pry"
|
11
|
+
# Pry.start
|
12
|
+
|
13
|
+
require "irb"
|
14
|
+
IRB.start(__FILE__)
|
data/bin/setup
ADDED
data/exe/obfusc
ADDED
data/lib/obfusc/cli.rb
ADDED
@@ -0,0 +1,93 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Obfusc
|
4
|
+
# This model receive and process ARGV from ./exe/obfusc script
|
5
|
+
class CLI
|
6
|
+
VALID_COMMANDS = %w[setup crypt decrypt show].freeze
|
7
|
+
|
8
|
+
attr_reader :argumetns, :options
|
9
|
+
|
10
|
+
def initialize(arguments)
|
11
|
+
@arguments = arguments
|
12
|
+
@options = {}
|
13
|
+
end
|
14
|
+
|
15
|
+
def run
|
16
|
+
configure
|
17
|
+
perform(@arguments.shift)
|
18
|
+
end
|
19
|
+
|
20
|
+
protected
|
21
|
+
|
22
|
+
def perform(command)
|
23
|
+
unless VALID_COMMANDS.include?(command)
|
24
|
+
puts parser.help
|
25
|
+
return
|
26
|
+
end
|
27
|
+
config = Obfusc::Config.new(@options)
|
28
|
+
class_name = "#{command[0].upcase}#{command[1..-1]}Command"
|
29
|
+
Obfusc.const_get(class_name).call(config, *@arguments)
|
30
|
+
end
|
31
|
+
|
32
|
+
def configure
|
33
|
+
parser.parse!(@arguments)
|
34
|
+
end
|
35
|
+
|
36
|
+
# rubocop:disable BlockLength,MethodLength,AbcSize
|
37
|
+
def parser
|
38
|
+
@parser = OptionParser.new do |opts|
|
39
|
+
opts.banner = 'Usage: obfusc <command> <arguments> <options>'
|
40
|
+
opts.separator ''
|
41
|
+
opts.separator 'Commands:'
|
42
|
+
VALID_COMMANDS.each do |command|
|
43
|
+
opts.separator " * #{command}"
|
44
|
+
end
|
45
|
+
|
46
|
+
opts.separator ''
|
47
|
+
opts.separator 'Specific options:'
|
48
|
+
|
49
|
+
opts.on('-c', '--config FILENAME',
|
50
|
+
'Using a different ".obfusc.cnf" filename') do |filename|
|
51
|
+
@options[:config_path] = filename
|
52
|
+
end
|
53
|
+
|
54
|
+
opts.on(
|
55
|
+
'-e',
|
56
|
+
'--extension STRING',
|
57
|
+
'Specify a custom file extension. (Default to "obfc")'
|
58
|
+
) do |extension|
|
59
|
+
@options[:extension] = extension
|
60
|
+
end
|
61
|
+
|
62
|
+
opts.on(
|
63
|
+
'-p',
|
64
|
+
'--prefix STRING',
|
65
|
+
'Specify a custom file prefix. (Default to "obfc")'
|
66
|
+
) do |prefix|
|
67
|
+
@options[:prefix] = prefix
|
68
|
+
end
|
69
|
+
|
70
|
+
opts.on('-v', '--[no-]verbose', 'Run verbosely') do |v|
|
71
|
+
@options[:verbose] = v
|
72
|
+
end
|
73
|
+
|
74
|
+
opts.on(
|
75
|
+
'-s',
|
76
|
+
'--[no-]simulate',
|
77
|
+
'Do a simulate run without executing actions'
|
78
|
+
) do |v|
|
79
|
+
@options[:simulate] = v
|
80
|
+
end
|
81
|
+
|
82
|
+
opts.separator ''
|
83
|
+
opts.separator 'Common options:'
|
84
|
+
|
85
|
+
opts.on_tail('-h', '--help', 'Show this message') do
|
86
|
+
puts opts
|
87
|
+
exit
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
# rubocop:enable BlockLength,MethodLength,AbcSize
|
92
|
+
end
|
93
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Obfusc
|
4
|
+
# Get/Set configurations with its default values.
|
5
|
+
class Config
|
6
|
+
attr_accessor :config_path, :extension, :verbose, :simulate
|
7
|
+
|
8
|
+
def initialize(options)
|
9
|
+
@config_path = options[:config_path]
|
10
|
+
@config_path ||= File.join(ENV['HOME'], '.obfusc.cnf')
|
11
|
+
|
12
|
+
@extension = options[:extension] || 'obfusc'
|
13
|
+
@verbose = options[:verbose] || false
|
14
|
+
@simulate = options[:simulate] || false
|
15
|
+
end
|
16
|
+
|
17
|
+
%i[simulate verbose].each do |method|
|
18
|
+
define_method "#{method}?" do
|
19
|
+
public_send("#{method}") == true
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def encryptor
|
24
|
+
@encryptor ||= Obfusc::Encryptor.new(self)
|
25
|
+
end
|
26
|
+
|
27
|
+
def token
|
28
|
+
settings['token']
|
29
|
+
end
|
30
|
+
|
31
|
+
def secret
|
32
|
+
settings['secret']
|
33
|
+
end
|
34
|
+
|
35
|
+
def log(msg)
|
36
|
+
puts("DEBUG: #{msg}") if verbose?
|
37
|
+
end
|
38
|
+
|
39
|
+
def dry_run
|
40
|
+
return unless block_given?
|
41
|
+
|
42
|
+
yield unless simulate?
|
43
|
+
end
|
44
|
+
|
45
|
+
protected
|
46
|
+
|
47
|
+
def settings
|
48
|
+
@settings ||= YAML.load_file(config_path)
|
49
|
+
rescue Errno::ENOENT
|
50
|
+
puts "No such file #{config_path}."
|
51
|
+
puts "Use: `obfusc setup generate' to generate it"
|
52
|
+
{}
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
@@ -0,0 +1,73 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Obfusc
|
4
|
+
# Commom methods shared between CryptCommand and DecryptCommand models.
|
5
|
+
# Children models only overwrite `show_usage` and files.
|
6
|
+
class EncryptorCommandBase
|
7
|
+
COMMANDS = %w[move copy].freeze
|
8
|
+
CURRENT_DIR = './'.freeze
|
9
|
+
|
10
|
+
def initialize(config, from, to)
|
11
|
+
@config = config
|
12
|
+
|
13
|
+
@from = from || CURRENT_DIR
|
14
|
+
@to = to || CURRENT_DIR
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.call(config, *args)
|
18
|
+
command, from, to = args
|
19
|
+
model = new(config, from, to)
|
20
|
+
command = 'show_usage' unless COMMANDS.include?(command)
|
21
|
+
model.public_send(command)
|
22
|
+
end
|
23
|
+
|
24
|
+
def show_usage
|
25
|
+
raise NotImplementedError
|
26
|
+
end
|
27
|
+
|
28
|
+
def files
|
29
|
+
raise NotImplementedError
|
30
|
+
end
|
31
|
+
|
32
|
+
def move
|
33
|
+
files.each_with_index do |(from, to), index|
|
34
|
+
create_target_base_directory if index.zero?
|
35
|
+
create_directory_from_file(to)
|
36
|
+
@config.log("mv #{from} #{to}")
|
37
|
+
@config.dry_run do
|
38
|
+
FileUtils.mv(from, to, verbose: @config.verbose?)
|
39
|
+
end
|
40
|
+
end.size
|
41
|
+
end
|
42
|
+
|
43
|
+
def copy
|
44
|
+
files.each_with_index do |(from, to), index|
|
45
|
+
create_target_base_directory if index.zero?
|
46
|
+
create_directory_from_file(to)
|
47
|
+
@config.log("cp #{from} #{to}")
|
48
|
+
@config.dry_run do
|
49
|
+
FileUtils.cp(from, to, verbose: @config.verbose?)
|
50
|
+
end
|
51
|
+
end.size
|
52
|
+
end
|
53
|
+
|
54
|
+
protected
|
55
|
+
|
56
|
+
def create_directory_from_file(path)
|
57
|
+
return if File.directory?(path)
|
58
|
+
dirname = File.dirname(path)
|
59
|
+
return if File.expand_path(dirname) == File.expand_path(@to)
|
60
|
+
|
61
|
+
@config.log("mkdir -p #{dirname}")
|
62
|
+
@config.dry_run { FileUtils.mkdir_p(dirname) }
|
63
|
+
end
|
64
|
+
|
65
|
+
def create_target_base_directory
|
66
|
+
return if @to == CURRENT_DIR
|
67
|
+
return if File.directory?(@to)
|
68
|
+
|
69
|
+
@config.log("mkdir -p #{@to}")
|
70
|
+
@config.dry_run { FileUtils.mkdir_p(@to) }
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'obfusc/commands/concerns/encryptor_command_base'
|
4
|
+
|
5
|
+
module Obfusc
|
6
|
+
# Perform tasks related `crypt` command
|
7
|
+
class CryptCommand < Obfusc::EncryptorCommandBase
|
8
|
+
# rubocop:disable MethodLength
|
9
|
+
def show_usage
|
10
|
+
usage = <<-TEXT.gsub(' ', '')
|
11
|
+
Usage:
|
12
|
+
$ obfusc crypt <* #{COMMANDS.join('|')}> <* from> <to>
|
13
|
+
<* > Required arguments
|
14
|
+
|
15
|
+
Action:
|
16
|
+
move: Files will be moved to the target.
|
17
|
+
copy: Keep existing files and generate a copy.
|
18
|
+
|
19
|
+
Files:
|
20
|
+
from: Relative or absolute of obfuscated directory/file. You can also use wildcards like "*" or "**".
|
21
|
+
to: Relative or absolute directory where un-obfuscated files will be stored. (Default to current directory)
|
22
|
+
TEXT
|
23
|
+
puts usage
|
24
|
+
end
|
25
|
+
# rubocop:enable MethodLength
|
26
|
+
|
27
|
+
protected
|
28
|
+
|
29
|
+
def files
|
30
|
+
recursive_from = File.join(@from, '**/{.*,*}') if File.directory?(@from)
|
31
|
+
Dir.glob(recursive_from || @from).each_with_object({}) do |path, memo|
|
32
|
+
next if File.directory?(path)
|
33
|
+
next if File.symlink?(path)
|
34
|
+
memo[path] = File.join(@to, @config.encryptor.encrypt(path))
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'obfusc/commands/concerns/encryptor_command_base'
|
4
|
+
|
5
|
+
module Obfusc
|
6
|
+
# Perform tasks related `decrypt` command
|
7
|
+
class DecryptCommand < Obfusc::EncryptorCommandBase
|
8
|
+
# rubocop:disable MethodLength
|
9
|
+
def show_usage
|
10
|
+
usage = <<-TEXT.gsub(' ', '')
|
11
|
+
Usage:
|
12
|
+
$ obfusc decrypt <* #{COMMANDS.join('|')}> <* from> <to>
|
13
|
+
<* > Required arguments
|
14
|
+
|
15
|
+
Action:
|
16
|
+
move: Files will be moved to the target.
|
17
|
+
copy: Keep existing files and generate a copy.
|
18
|
+
|
19
|
+
Files:
|
20
|
+
from: Relative or absolute directory/file be obfuscated. You can also use wildcards like "*" or "**".
|
21
|
+
to: Relative or absolute directory where obfuscated files will be stored. (Default to current directory)
|
22
|
+
TEXT
|
23
|
+
puts usage
|
24
|
+
end
|
25
|
+
# rubocop:enable MethodLength
|
26
|
+
|
27
|
+
protected
|
28
|
+
|
29
|
+
def files
|
30
|
+
recursive_from = File.join(@from, '**/{.*,*}') if File.directory?(@from)
|
31
|
+
Dir.glob(recursive_from || @from).each_with_object({}) do |path, memo|
|
32
|
+
next if File.directory?(path)
|
33
|
+
next if File.symlink?(path)
|
34
|
+
basename = File.basename(path)
|
35
|
+
next unless @config.encryptor.obfuscated?(basename)
|
36
|
+
memo[path] = File.join(@to, @config.encryptor.decrypt(basename))
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Obfusc
|
4
|
+
# Perform tasks related `setup` command
|
5
|
+
class SetupCommand
|
6
|
+
COMMANDS = %w[generate show].freeze
|
7
|
+
|
8
|
+
def initialize(config)
|
9
|
+
@config = config
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.call(config, *args)
|
13
|
+
model = new(config)
|
14
|
+
command = args.first
|
15
|
+
command = 'show_usage' unless COMMANDS.include?(command)
|
16
|
+
model.public_send(command)
|
17
|
+
end
|
18
|
+
|
19
|
+
def show_usage
|
20
|
+
puts "Usage:\nobfusc setup <#{COMMANDS.join('|')}>"
|
21
|
+
end
|
22
|
+
|
23
|
+
def generate
|
24
|
+
File.open(config_file, 'w') do |f|
|
25
|
+
f.write tokenize(Obfusc::Random.generate!)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def show
|
30
|
+
unless File.exist?(config_file)
|
31
|
+
puts "#{config_file} does not exist.\nUse: `obfusc setup generate'"
|
32
|
+
return
|
33
|
+
end
|
34
|
+
YAML.load_file(config_file).each do |key, value|
|
35
|
+
puts "#{key}:"
|
36
|
+
puts "---> #{value.inspect}"
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
protected
|
41
|
+
|
42
|
+
def tokenize(characters_hash)
|
43
|
+
token = ''
|
44
|
+
secret = ''
|
45
|
+
characters_hash.sort_by { rand }.each do |key, value|
|
46
|
+
token += key
|
47
|
+
secret += value
|
48
|
+
end
|
49
|
+
YAML.dump(
|
50
|
+
'prefix' => @config.prefix,
|
51
|
+
'suffix' => @config.extension,
|
52
|
+
'token' => token,
|
53
|
+
'secret' => secret
|
54
|
+
)
|
55
|
+
end
|
56
|
+
|
57
|
+
def config_file
|
58
|
+
@config.config_path
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Obfusc
|
4
|
+
# Perform tasks related `show` command
|
5
|
+
class ShowCommand
|
6
|
+
|
7
|
+
def initialize(config, source)
|
8
|
+
@config = config
|
9
|
+
@source = source
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.call(config, *args)
|
13
|
+
source = args.first
|
14
|
+
model = new(config, source)
|
15
|
+
model.public_send(File.exist?(source) ? :run : :show_usage)
|
16
|
+
end
|
17
|
+
|
18
|
+
def run
|
19
|
+
files.each do |from, to|
|
20
|
+
puts "#{from}:"
|
21
|
+
puts "---> #{to}"
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def show_usage
|
26
|
+
usage = <<-TEXT.gsub(' ', '')
|
27
|
+
Usage:
|
28
|
+
$ obfusc show <source>
|
29
|
+
|
30
|
+
Files:
|
31
|
+
source: Relative or absolute directory where obfuscated files are stored. (Default to current directory)
|
32
|
+
TEXT
|
33
|
+
puts usage
|
34
|
+
end
|
35
|
+
|
36
|
+
protected
|
37
|
+
|
38
|
+
def files
|
39
|
+
recursive_from = File.join(@source, '**/{.*,*}') if File.directory?(@source)
|
40
|
+
Dir.glob(recursive_from || @source).each_with_object({}) do |path, memo|
|
41
|
+
next if File.directory?(path)
|
42
|
+
next if File.symlink?(path)
|
43
|
+
basename = File.basename(path)
|
44
|
+
next unless @config.encryptor.obfuscated?(basename)
|
45
|
+
memo[path] = @config.encryptor.decrypt(basename)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Obfusc
|
4
|
+
# Get/Set configurations with its default values.
|
5
|
+
class Config
|
6
|
+
attr_accessor :config_path, :extension, :verbose, :simulate, :prefix
|
7
|
+
|
8
|
+
def initialize(options)
|
9
|
+
@config_path = options[:config_path]
|
10
|
+
@config_path ||= File.join(ENV['HOME'], '.obfusc.cnf')
|
11
|
+
|
12
|
+
@extension = options[:extension] || 'obfusc'
|
13
|
+
@prefix = options[:prefix] || 'obfusc'
|
14
|
+
@verbose = options[:verbose] || false
|
15
|
+
@simulate = options[:simulate] || false
|
16
|
+
end
|
17
|
+
|
18
|
+
%i[simulate verbose].each do |method|
|
19
|
+
define_method "#{method}?" do
|
20
|
+
public_send("#{method}") == true
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def encryptor
|
25
|
+
@encryptor ||= Obfusc::Encryptor.new(self)
|
26
|
+
end
|
27
|
+
|
28
|
+
def token
|
29
|
+
settings['token']
|
30
|
+
end
|
31
|
+
|
32
|
+
def secret
|
33
|
+
settings['secret']
|
34
|
+
end
|
35
|
+
|
36
|
+
def log(msg)
|
37
|
+
puts("DEBUG: #{msg}") if verbose?
|
38
|
+
end
|
39
|
+
|
40
|
+
def dry_run
|
41
|
+
return unless block_given?
|
42
|
+
|
43
|
+
yield unless simulate?
|
44
|
+
end
|
45
|
+
|
46
|
+
protected
|
47
|
+
|
48
|
+
def settings
|
49
|
+
@settings ||= YAML.load_file(config_path)
|
50
|
+
rescue Errno::ENOENT
|
51
|
+
puts "No such file #{config_path}."
|
52
|
+
puts "Use: `obfusc setup generate' to generate it"
|
53
|
+
{}
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
@@ -0,0 +1,80 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Obfusc
|
4
|
+
# Recursive find files from origin or pattern
|
5
|
+
class Encryptor
|
6
|
+
SEP_FROM = '/'.freeze
|
7
|
+
SEP_TO = '___|___'.freeze
|
8
|
+
|
9
|
+
def initialize(config)
|
10
|
+
@config = config
|
11
|
+
@prefix = "#{config.prefix}__"
|
12
|
+
@suffix = ".#{config.extension}"
|
13
|
+
end
|
14
|
+
|
15
|
+
def encrypt(path)
|
16
|
+
crypted_filename = expand_path_for_encrypt(path).map do |step|
|
17
|
+
step.chars.map { |char| charlist[char] || char }.join
|
18
|
+
end.join(SEP_TO)
|
19
|
+
|
20
|
+
[@prefix, crypted_filename, @suffix].join
|
21
|
+
end
|
22
|
+
|
23
|
+
def decrypt(path)
|
24
|
+
expand_path_for_decrypt(path).join(SEP_FROM)
|
25
|
+
end
|
26
|
+
|
27
|
+
def obfuscated?(file)
|
28
|
+
!!(file =~ obfuscated_expression)
|
29
|
+
end
|
30
|
+
|
31
|
+
protected
|
32
|
+
|
33
|
+
def expand_path_for_encrypt(path)
|
34
|
+
parts = []
|
35
|
+
path.split(SEP_FROM).each do |part|
|
36
|
+
parts.push(*try_decrypt(part).split(SEP_FROM))
|
37
|
+
end
|
38
|
+
parts
|
39
|
+
end
|
40
|
+
|
41
|
+
def expand_path_for_decrypt(path, memo = [])
|
42
|
+
return memo if String(path).length.zero?
|
43
|
+
|
44
|
+
if path =~ obfuscated_expression
|
45
|
+
parts = normalize(path).split(SEP_TO)
|
46
|
+
return [*memo, *parts.map { |part| decrypt_segment(part) }]
|
47
|
+
end
|
48
|
+
|
49
|
+
dir, new_path = path.split(SEP_FROM, 2)
|
50
|
+
expand_path_for_decrypt(new_path, [*memo, dir])
|
51
|
+
end
|
52
|
+
|
53
|
+
def decrypt_segment(segment)
|
54
|
+
segment.chars.map { |char| charlist.key(char) || char }.join
|
55
|
+
end
|
56
|
+
|
57
|
+
def try_decrypt(step)
|
58
|
+
return step unless step =~ obfuscated_expression
|
59
|
+
decrypt(step)
|
60
|
+
end
|
61
|
+
|
62
|
+
def obfuscated_expression
|
63
|
+
/^(#{Regexp.escape(@prefix)}).*(#{Regexp.escape(@suffix)})$/
|
64
|
+
end
|
65
|
+
|
66
|
+
def charlist
|
67
|
+
@charlist ||= begin
|
68
|
+
keys = @config.token.split('')
|
69
|
+
values = @config.secret.split('')
|
70
|
+
Hash[keys.zip(values)]
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
def normalize(path)
|
75
|
+
path.sub!(/^(#{Regexp.escape(@prefix)})/, '')
|
76
|
+
path.sub!(/(#{Regexp.escape(@suffix)})$/, '')
|
77
|
+
path
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Obfusc
|
4
|
+
# Grab most comon characters and generate a random list of key and value
|
5
|
+
class Random
|
6
|
+
DIGIT = (0x30..0x39).map(&:chr)
|
7
|
+
ALPHA = (0x41..0x5a).map(&:chr) + (0x61..0x7a).map(&:chr)
|
8
|
+
SPECIAL = [
|
9
|
+
' ', '-', '_', ',', ':', ';', '=', '@', '[', ']', '(', ')', '{', '}', '|'
|
10
|
+
].freeze
|
11
|
+
|
12
|
+
def self.generate!
|
13
|
+
hash = {}
|
14
|
+
randonize!(hash, DIGIT + ALPHA)
|
15
|
+
randonize!(hash, SPECIAL)
|
16
|
+
hash
|
17
|
+
end
|
18
|
+
|
19
|
+
private_class_method def self.randonize!(memo, source)
|
20
|
+
source.sort_by { rand }.each do |char|
|
21
|
+
list = source - (memo.values & source)
|
22
|
+
loop do
|
23
|
+
memo[char] = list.sample
|
24
|
+
break if list.size <= 1
|
25
|
+
break if memo[char] != char
|
26
|
+
end
|
27
|
+
end
|
28
|
+
memo
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
data/lib/obfusc.rb
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'optparse'
|
4
|
+
require 'yaml'
|
5
|
+
require 'fileutils'
|
6
|
+
|
7
|
+
require 'obfusc/cli'
|
8
|
+
require 'obfusc/config'
|
9
|
+
require 'obfusc/encryptor'
|
10
|
+
require 'obfusc/random'
|
11
|
+
require 'obfusc/version'
|
12
|
+
|
13
|
+
Dir["#{File.dirname(__FILE__)}/obfusc/commands/*_command.rb"].each do |file|
|
14
|
+
require file
|
15
|
+
end
|
16
|
+
|
17
|
+
# Script to obfuscate directories or files using a unique token/secret key.
|
18
|
+
module Obfusc
|
19
|
+
end
|
data/obfusc.gemspec
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'obfusc/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = 'obfusc'
|
8
|
+
spec.version = Obfusc::VERSION
|
9
|
+
spec.authors = ['Marcos G. Zimmermann']
|
10
|
+
spec.email = ['mgzmaster@gmail.com']
|
11
|
+
spec.license = 'MIT'
|
12
|
+
|
13
|
+
spec.summary = 'Command line tool to obfuscate files'
|
14
|
+
spec.description = 'Simple script to obfuscate one or more files' \
|
15
|
+
' preserving the directory tree'
|
16
|
+
spec.homepage = 'https://github.com/marcosgz/obfusc'
|
17
|
+
|
18
|
+
spec.files = `git ls-files -z`.split("\x0").reject do |f|
|
19
|
+
f.match(%r{^(test|spec|features)/})
|
20
|
+
end
|
21
|
+
spec.bindir = 'exe'
|
22
|
+
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
23
|
+
spec.require_paths = ['lib']
|
24
|
+
|
25
|
+
spec.add_development_dependency 'bundler', '~> 1.16'
|
26
|
+
spec.add_development_dependency 'rake', '~> 10.0'
|
27
|
+
spec.add_development_dependency 'rspec', '~> 3.0'
|
28
|
+
end
|
metadata
ADDED
@@ -0,0 +1,111 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: obfusc
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Marcos G. Zimmermann
|
8
|
+
autorequire:
|
9
|
+
bindir: exe
|
10
|
+
cert_chain: []
|
11
|
+
date: 2018-01-31 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: bundler
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.16'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.16'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rake
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '10.0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '10.0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rspec
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '3.0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '3.0'
|
55
|
+
description: Simple script to obfuscate one or more files preserving the directory
|
56
|
+
tree
|
57
|
+
email:
|
58
|
+
- mgzmaster@gmail.com
|
59
|
+
executables:
|
60
|
+
- obfusc
|
61
|
+
extensions: []
|
62
|
+
extra_rdoc_files: []
|
63
|
+
files:
|
64
|
+
- ".gitignore"
|
65
|
+
- ".rspec"
|
66
|
+
- ".travis.yml"
|
67
|
+
- Gemfile
|
68
|
+
- Gemfile.lock
|
69
|
+
- README.md
|
70
|
+
- Rakefile
|
71
|
+
- bin/console
|
72
|
+
- bin/setup
|
73
|
+
- exe/obfusc
|
74
|
+
- lib/obfusc.rb
|
75
|
+
- lib/obfusc/cli.rb
|
76
|
+
- lib/obfusc/commands/concerns/config.rb
|
77
|
+
- lib/obfusc/commands/concerns/encryptor_command_base.rb
|
78
|
+
- lib/obfusc/commands/crypt_command.rb
|
79
|
+
- lib/obfusc/commands/decrypt_command.rb
|
80
|
+
- lib/obfusc/commands/setup_command.rb
|
81
|
+
- lib/obfusc/commands/show_command.rb
|
82
|
+
- lib/obfusc/config.rb
|
83
|
+
- lib/obfusc/encryptor.rb
|
84
|
+
- lib/obfusc/random.rb
|
85
|
+
- lib/obfusc/version.rb
|
86
|
+
- obfusc.gemspec
|
87
|
+
homepage: https://github.com/marcosgz/obfusc
|
88
|
+
licenses:
|
89
|
+
- MIT
|
90
|
+
metadata: {}
|
91
|
+
post_install_message:
|
92
|
+
rdoc_options: []
|
93
|
+
require_paths:
|
94
|
+
- lib
|
95
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
96
|
+
requirements:
|
97
|
+
- - ">="
|
98
|
+
- !ruby/object:Gem::Version
|
99
|
+
version: '0'
|
100
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
101
|
+
requirements:
|
102
|
+
- - ">="
|
103
|
+
- !ruby/object:Gem::Version
|
104
|
+
version: '0'
|
105
|
+
requirements: []
|
106
|
+
rubyforge_project:
|
107
|
+
rubygems_version: 2.5.1
|
108
|
+
signing_key:
|
109
|
+
specification_version: 4
|
110
|
+
summary: Command line tool to obfuscate files
|
111
|
+
test_files: []
|