knocker 0.2.3
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 +7 -0
- data/.gitignore +17 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +81 -0
- data/Rakefile +14 -0
- data/bin/nkr +28 -0
- data/examples/config +18 -0
- data/knocker.gemspec +24 -0
- data/lib/knocker.rb +16 -0
- data/lib/knocker/errors.rb +10 -0
- data/lib/knocker/parser.rb +29 -0
- data/lib/knocker/pattern.rb +56 -0
- data/lib/knocker/version.rb +3 -0
- metadata +101 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 6b4289625cc8b8ca43224fc4529d4472a91a2aeb
|
4
|
+
data.tar.gz: eeda48021083930707232a70ead8f0d268d0aca4
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 70096d1ec8d32d66acee9e44f3a2b640d214f4ca61e7c8352dc7338f65d7048ec2acd964fb9ad9a7feaf50a9dee0ce1116ad78c588afe87336fdbd2c39a97f86
|
7
|
+
data.tar.gz: 67a4544b1cc2c67de4e647b1d56ae498e7692399c61ce04d455a3ddce214b538324fc4cc0cc8810b87f33582d804df8654e010fd91e53265910f38fbfed6fe2e
|
data/.gitignore
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2014 Robert McLeod
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,81 @@
|
|
1
|
+
# Knocker
|
2
|
+
|
3
|
+
I wanted to use knock servers but wasn't sure how to remember all the knock patterns, plus I pretty much always want to run specific commands straight after knocking.
|
4
|
+
|
5
|
+
I also love `.ssh/config` files (if you don't use one, you are missing out!), so simple yet so powerful.
|
6
|
+
|
7
|
+
## Installation
|
8
|
+
|
9
|
+
Add this line to your application's Gemfile:
|
10
|
+
|
11
|
+
gem 'knocker'
|
12
|
+
|
13
|
+
And then execute:
|
14
|
+
|
15
|
+
$ bundle
|
16
|
+
|
17
|
+
Or install it yourself as:
|
18
|
+
|
19
|
+
$ gem install knocker
|
20
|
+
|
21
|
+
## Usage
|
22
|
+
|
23
|
+
Like an SSH config is powerful for connecting to SSH daemons:
|
24
|
+
|
25
|
+
```
|
26
|
+
# SSH config file
|
27
|
+
Host myvps
|
28
|
+
Hostname vps.example.com
|
29
|
+
User robert
|
30
|
+
Port 22022
|
31
|
+
DynamicForward 50000
|
32
|
+
LocalForward 3000:localhost:3000
|
33
|
+
ForwardX11 yes
|
34
|
+
```
|
35
|
+
|
36
|
+
I want knocker to be powerful for connecting to knock daemons:
|
37
|
+
|
38
|
+
Each config file stores knock patterns which include:
|
39
|
+
|
40
|
+
* hostname
|
41
|
+
* knock specs
|
42
|
+
* commands to run after knocking
|
43
|
+
|
44
|
+
```
|
45
|
+
# Knocker config file
|
46
|
+
# keep this secret, knock patterns are almost like passwords
|
47
|
+
pattern pvtchatops
|
48
|
+
host myvps.example.com
|
49
|
+
u 5445
|
50
|
+
t 4456
|
51
|
+
t 63854
|
52
|
+
c xchat --url=irc://myvps.example.com:36777/chatops
|
53
|
+
```
|
54
|
+
|
55
|
+
So when you run `nkr pvtchatops` it actually runs two commands:
|
56
|
+
|
57
|
+
* The knock client command: `knock myvps.example.com 5445:udp 4456:tcp 63854:tcp`
|
58
|
+
* The post command: `xchat --url=irc://myvps.example.com:36777/chatops`
|
59
|
+
|
60
|
+
Easy!
|
61
|
+
|
62
|
+
### The rules
|
63
|
+
|
64
|
+
As you saw, the config syntax is simple.
|
65
|
+
|
66
|
+
* h and then the hostname/ip to connect to
|
67
|
+
* t and the port number for a tcp knock (multiples allowed)
|
68
|
+
* u and the port number for a udp knock (multiples allowed)
|
69
|
+
* c and the command to run after knocking (multiples allowed)
|
70
|
+
|
71
|
+
**Mix this with SSH config files and you will an unstoppable sysadmin!**
|
72
|
+
|
73
|
+
**KEEP THE CONFIG FILE SECRET!!!**
|
74
|
+
|
75
|
+
## Contributing
|
76
|
+
|
77
|
+
1. Fork it ( http://github.com/penguinpowernz/knocker/fork )
|
78
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
79
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
80
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
81
|
+
5. Create new Pull Request
|
data/Rakefile
ADDED
data/bin/nkr
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'knocker'
|
4
|
+
require 'fileutils'
|
5
|
+
|
6
|
+
name = ARGV[0]
|
7
|
+
|
8
|
+
begin
|
9
|
+
pattern = Knocker.pattern(name)
|
10
|
+
system pattern.knock_command
|
11
|
+
|
12
|
+
pattern.post_commands.each do |cmd|
|
13
|
+
system cmd
|
14
|
+
end
|
15
|
+
rescue Knocker::Errors::ConfigNotFound
|
16
|
+
print "No config found, create one at #{Knocker.config}? [y/n]: "
|
17
|
+
FileUtils.touch Knocker.config if STDIN.gets.match /y/i
|
18
|
+
rescue Knocker::Errors::PatternNotFound
|
19
|
+
abort "No such pattern #{name}"
|
20
|
+
rescue Knocker::Errors::NoHostSpecified
|
21
|
+
abort "No host specified in pattern #{name}"
|
22
|
+
rescue Knocker::Errors::NoKnockSpecified
|
23
|
+
abort "No port-knocks specified in pattern #{name}"
|
24
|
+
rescue Knocker::Errors::InvalidProtocol => e
|
25
|
+
abort "Invalid protocol #{e.message} in pattern #{name}"
|
26
|
+
rescue Knocker::Errors::InvalidPort => e
|
27
|
+
abort "Invalid port #{e.message} in pattern #{name}"
|
28
|
+
end
|
data/examples/config
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
# Knocker config file
|
2
|
+
|
3
|
+
# pattern name
|
4
|
+
# u udp_port knock_count
|
5
|
+
# t tcp_port knock_count
|
6
|
+
# c command to run
|
7
|
+
|
8
|
+
# pattern vps1ssh
|
9
|
+
# u 4444 3
|
10
|
+
# t 3333 4
|
11
|
+
# u 7685 2
|
12
|
+
# c ssh usavps01
|
13
|
+
|
14
|
+
# pattern chatops
|
15
|
+
# u 2456 4
|
16
|
+
# t 6767 5
|
17
|
+
# t 2245 3
|
18
|
+
# c xchat irc://my.private.irc:26777/chatops
|
data/knocker.gemspec
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'knocker/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "knocker"
|
8
|
+
spec.version = Knocker::VERSION
|
9
|
+
spec.authors = ["Robert McLeod"]
|
10
|
+
spec.email = ["robert@penguinpower.co.nz"]
|
11
|
+
spec.summary = %q{Uses stored config to knocks on knock daemons}
|
12
|
+
spec.description = %q{Uses a config file to knock on a host and execute command(s), tries to mimic .ssh/config function}
|
13
|
+
spec.homepage = "https://github.com/penguinpowernz/knocker"
|
14
|
+
spec.license = "MIT"
|
15
|
+
|
16
|
+
spec.files = `git ls-files -z`.split("\x0")
|
17
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
18
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
|
+
spec.require_paths = ["lib"]
|
20
|
+
|
21
|
+
spec.add_development_dependency "bundler", "~> 1.5"
|
22
|
+
spec.add_development_dependency "rake"
|
23
|
+
spec.add_development_dependency "rspec"
|
24
|
+
end
|
data/lib/knocker.rb
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
require "knocker/version"
|
2
|
+
require "knocker/errors"
|
3
|
+
require "knocker/parser"
|
4
|
+
require "knocker/pattern"
|
5
|
+
|
6
|
+
module Knocker
|
7
|
+
class << self
|
8
|
+
def config
|
9
|
+
"#{ENV["HOME"]}/.config/knocker/config"
|
10
|
+
end
|
11
|
+
|
12
|
+
def pattern(name)
|
13
|
+
Knocker::Parser.new(config).find(name).to_hash
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,10 @@
|
|
1
|
+
module Knocker
|
2
|
+
module Errors
|
3
|
+
class ConfigNotFound < StandardError; end
|
4
|
+
class PatternNotFound < StandardError; end
|
5
|
+
class NoHostSpecified < StandardError; end
|
6
|
+
class NoKnockSpecified < StandardError; end
|
7
|
+
class InvalidProtocol < StandardError; end
|
8
|
+
class InvalidPort < StandardError; end
|
9
|
+
end
|
10
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module Knocker
|
2
|
+
class Parser
|
3
|
+
def initialize(config)
|
4
|
+
raise Knocker::Errors::ConfigNotFound unless File.exist? config
|
5
|
+
@config = File.read(config).reject! {|line| line.start_with? "#"}
|
6
|
+
end
|
7
|
+
|
8
|
+
def find(name)
|
9
|
+
has_pattern! name
|
10
|
+
Pattern.new name, extract(name)
|
11
|
+
end
|
12
|
+
|
13
|
+
private
|
14
|
+
|
15
|
+
def has_pattern!(name)
|
16
|
+
raise Knocker::Errors::PatterNotFound unless
|
17
|
+
@config.include? "pattern #{name}"
|
18
|
+
end
|
19
|
+
|
20
|
+
def extract(name)
|
21
|
+
start = @config.lines.index("pattern #{name}")
|
22
|
+
|
23
|
+
@config.lines[start..-1].collect { |line|
|
24
|
+
break if line.blank?
|
25
|
+
line
|
26
|
+
}.join("\n")
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
module Knocker
|
2
|
+
class Pattern
|
3
|
+
attr_reader :name
|
4
|
+
|
5
|
+
def initialize(name, text)
|
6
|
+
@name = name
|
7
|
+
@text = text
|
8
|
+
end
|
9
|
+
|
10
|
+
def to_hash
|
11
|
+
{
|
12
|
+
:host => host,
|
13
|
+
:knock_command => knock_command,
|
14
|
+
:name => @name
|
15
|
+
}
|
16
|
+
end
|
17
|
+
|
18
|
+
def host
|
19
|
+
host = @text.scan(/ h (.*)/).flatten.first
|
20
|
+
raise Knocker::Errors::NoHostSpecified if host.nil? or host.blank?
|
21
|
+
end
|
22
|
+
|
23
|
+
def knock_command
|
24
|
+
patterns = []
|
25
|
+
|
26
|
+
patterns = @text.scan(/ ([ut]) (\d+)/).collect do |proto, port|
|
27
|
+
valid_port!(port)
|
28
|
+
"#{port}:#{protocol!(proto)}"
|
29
|
+
end
|
30
|
+
|
31
|
+
raise Knocker::Errors::NoKnockSpecified if patterns.empty?
|
32
|
+
|
33
|
+
"knock #{host} #{patterns.join(" ")}"
|
34
|
+
end
|
35
|
+
|
36
|
+
def post_commands
|
37
|
+
cmds = @text.scan(/^ c (.*)$/)
|
38
|
+
cmds.map! do |cmd|
|
39
|
+
cmd.gsub! /\$host/, host
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
private
|
44
|
+
|
45
|
+
def protocol!(char)
|
46
|
+
return "udp" if char == "u"
|
47
|
+
return "tcp" if char == "t"
|
48
|
+
raise Knocker::Errors::InvalidProtocol, char
|
49
|
+
end
|
50
|
+
|
51
|
+
def valid_port!(port)
|
52
|
+
raise Errors::InvalidPort, port if port.to_i.zero?
|
53
|
+
raise Errors::InvalidPort, port if port.to_i > 65535
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
metadata
ADDED
@@ -0,0 +1,101 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: knocker
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.2.3
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Robert McLeod
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2014-03-14 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.5'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.5'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rake
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '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: '0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
description: Uses a config file to knock on a host and execute command(s), tries to
|
56
|
+
mimic .ssh/config function
|
57
|
+
email:
|
58
|
+
- robert@penguinpower.co.nz
|
59
|
+
executables:
|
60
|
+
- nkr
|
61
|
+
extensions: []
|
62
|
+
extra_rdoc_files: []
|
63
|
+
files:
|
64
|
+
- ".gitignore"
|
65
|
+
- Gemfile
|
66
|
+
- LICENSE.txt
|
67
|
+
- README.md
|
68
|
+
- Rakefile
|
69
|
+
- bin/nkr
|
70
|
+
- examples/config
|
71
|
+
- knocker.gemspec
|
72
|
+
- lib/knocker.rb
|
73
|
+
- lib/knocker/errors.rb
|
74
|
+
- lib/knocker/parser.rb
|
75
|
+
- lib/knocker/pattern.rb
|
76
|
+
- lib/knocker/version.rb
|
77
|
+
homepage: https://github.com/penguinpowernz/knocker
|
78
|
+
licenses:
|
79
|
+
- MIT
|
80
|
+
metadata: {}
|
81
|
+
post_install_message:
|
82
|
+
rdoc_options: []
|
83
|
+
require_paths:
|
84
|
+
- lib
|
85
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - ">="
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '0'
|
90
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
91
|
+
requirements:
|
92
|
+
- - ">="
|
93
|
+
- !ruby/object:Gem::Version
|
94
|
+
version: '0'
|
95
|
+
requirements: []
|
96
|
+
rubyforge_project:
|
97
|
+
rubygems_version: 2.2.2
|
98
|
+
signing_key:
|
99
|
+
specification_version: 4
|
100
|
+
summary: Uses stored config to knocks on knock daemons
|
101
|
+
test_files: []
|