mini_uri 0.9.1
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 +1 -0
- data/Gemfile +4 -0
- data/License.md +21 -0
- data/README.md +66 -0
- data/Rakefile +8 -0
- data/lib/mini_uri.rb +50 -0
- data/mini_uri.gemspec +24 -0
- metadata +106 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 8bc5b0c532b9e09aa353ddc62aae101d7e428e10
|
4
|
+
data.tar.gz: fdc697dba42b5d81dc18610ee9b5550775d185bb
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 6d89b7cb28b6d63123f6b3fbf46f3f0dde2965359ec786732cca2cc8358d924f66f15866c451417a34ec4732536e0deac5719d11ad930acef9dd49dcecc0161c
|
7
|
+
data.tar.gz: 125c4a8c61eba66749e2d7ada7bad5b3f29519133f5aee8ad6c49e0c748937c2dd45060f3776e61958243fdf25171f69c4c9597b864d38732f427387bb857799
|
data/.gitignore
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
Gemfile.lock
|
data/Gemfile
ADDED
data/License.md
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2016 Alex Pilon
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
13
|
+
copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
21
|
+
SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,66 @@
|
|
1
|
+
# MiniUri
|
2
|
+
|
3
|
+
Generate short(ish), practically unguessable URI for app models, implemented in Plain Old Ruby. MiniUri uses reflection to create uniquely identifiable URI, so `Foo.new.to_muri` and `Bar.new.to_muri` will be different. Should your app use MiniUri to issue permalinks, the links are no longer valid if the secret changes or, as a result of the reflection if the namespace of your class changes (change module, change class name, etc).
|
4
|
+
|
5
|
+
NOTE: MiniUri is meant for a specific use case. It was designed for issuing links to "protected" or "unlisted" resources. Despite a cryptographic review, and the potential for use outside this use case, at this time I recommend it be used strictly for sharing unlisted resources (things that are public, but that you'd rather not have the masses and web crawlers have access to, like a sign-in portal tailored to a user or client). A future goal of this project is to allow for pre-authorized actions, however I will wait to see how the gem fares in the wild first.
|
6
|
+
|
7
|
+
Please load your secret to `ENV['MINI_URI_SECRET']`, MiniUri assumes no responsibility for your secret. Please make sure it is securely stored, and generated by a good random number generator. A good secret should be 256 bits in length.
|
8
|
+
|
9
|
+
NOTE: many secrets are encoded and stored as hex or base64, it is advised to remove the encoding or else risk diluting the entropy of your secret, for hex you can do the following (ruby 2):
|
10
|
+
|
11
|
+
```ruby
|
12
|
+
secret = '000E0000000000'
|
13
|
+
secret.length
|
14
|
+
# => 14
|
15
|
+
ENV["MINI_URI_SECRET"] = [secret].pack('H*')
|
16
|
+
ENV["MINI_URI_SECRET"].length
|
17
|
+
# => 7
|
18
|
+
```
|
19
|
+
For Base64 use the appropriate method in the Base64 standard library
|
20
|
+
|
21
|
+
## Installation
|
22
|
+
|
23
|
+
```
|
24
|
+
gem install mini_uri
|
25
|
+
```
|
26
|
+
|
27
|
+
## Usage
|
28
|
+
|
29
|
+
Include MiniUri in any of your app's models.
|
30
|
+
```ruby
|
31
|
+
require 'mini_uri'
|
32
|
+
|
33
|
+
class User
|
34
|
+
include MiniUri
|
35
|
+
|
36
|
+
attr_accessor :id
|
37
|
+
end
|
38
|
+
```
|
39
|
+
MiniUri assumes the model class has an integer attribute `:id` since this is the common practice, however you can generate on any integer value you want.
|
40
|
+
```ruby
|
41
|
+
ENV['MINI_URI_SECRET'] = 'this is a bad secret'
|
42
|
+
|
43
|
+
user = User.new
|
44
|
+
user.id = 12345
|
45
|
+
user.to_muri
|
46
|
+
# => "3D7-6xtqryABGqkHNGSieho1Do"
|
47
|
+
|
48
|
+
User.new.to_muri(12345)
|
49
|
+
# => "3D7-6xtqryABGqkHNGSieho1Do"
|
50
|
+
```
|
51
|
+
now say you have an endpoint `/user/:mini_uri`, in the corresponding controller you could retrieve the actual id and record
|
52
|
+
```ruby
|
53
|
+
def show
|
54
|
+
id = User.muri_to_id(params[:mini_uri])
|
55
|
+
if id == nil
|
56
|
+
render_404
|
57
|
+
else
|
58
|
+
@user = User.find(id)
|
59
|
+
end
|
60
|
+
end
|
61
|
+
```
|
62
|
+
|
63
|
+
## Special Thanks
|
64
|
+
* [Geoff Longman](https://github.com/glongman)
|
65
|
+
* [Carlisle Adams](http://www.site.uottawa.ca/~cadams/)
|
66
|
+
* [Everyone at Fullscript](http://fullscript.com/)
|
data/Rakefile
ADDED
data/lib/mini_uri.rb
ADDED
@@ -0,0 +1,50 @@
|
|
1
|
+
# MiniUri
|
2
|
+
# Author: Alex Pilon
|
3
|
+
# Email: apilo088@gmail.com
|
4
|
+
# Security considerations drawn from
|
5
|
+
# https://tools.ietf.org/html/rfc2104
|
6
|
+
# https://tools.ietf.org/html/rfc4868
|
7
|
+
# https://tools.ietf.org/html/rfc6234
|
8
|
+
|
9
|
+
require 'openssl'
|
10
|
+
require 'base62'
|
11
|
+
|
12
|
+
module MiniUri
|
13
|
+
|
14
|
+
DELIMITER = '-'
|
15
|
+
HMAC_SIZE = 16 # bytes
|
16
|
+
DIGEST = OpenSSL::Digest.new('sha256')
|
17
|
+
|
18
|
+
attr_reader :id
|
19
|
+
|
20
|
+
def MiniUri.included(klass)
|
21
|
+
klass.extend(ClassMethods)
|
22
|
+
end
|
23
|
+
|
24
|
+
def MiniUri.hmac(message, secret, n = HMAC_SIZE)
|
25
|
+
raise ArgumentError, "truncated hmacs should not be less than 10 bytes" if n > 32 || n < 10
|
26
|
+
# generate a 256 bit (32 byte) hmac, then truncate it to n bytes
|
27
|
+
hmac_truncated = OpenSSL::HMAC.digest(DIGEST, secret, message)[0, n]
|
28
|
+
# convert raw bytes to hex string (which doubles the size because of 2's complement)
|
29
|
+
# then convert to an integer, to be encoded finally to a base62 string
|
30
|
+
Digest::hexencode(hmac_truncated).hex.base62_encode
|
31
|
+
end
|
32
|
+
|
33
|
+
def to_muri(int_id = id)
|
34
|
+
raise ArgumentError, "id should be an Integer" unless int_id.is_a?(Integer)
|
35
|
+
encoded_id = int_id.base62_encode
|
36
|
+
encoded_id + DELIMITER + MiniUri.hmac(self.class.name + encoded_id, ENV["MINI_URI_SECRET"])
|
37
|
+
end
|
38
|
+
|
39
|
+
module ClassMethods
|
40
|
+
def muri_to_id(mini_uri)
|
41
|
+
raise ArgumentError, "mini_uri should be a String" unless mini_uri.is_a?(String)
|
42
|
+
args = mini_uri.strip.split(DELIMITER)
|
43
|
+
return nil if args.length != 2
|
44
|
+
encoded_id, expected_hmac = args
|
45
|
+
if expected_hmac == MiniUri.hmac(self.name + encoded_id, ENV["MINI_URI_SECRET"])
|
46
|
+
encoded_id.base62_decode
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
data/mini_uri.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
|
+
|
5
|
+
Gem::Specification.new do |spec|
|
6
|
+
spec.name = "mini_uri"
|
7
|
+
spec.version = "0.9.1"
|
8
|
+
spec.authors = ["Alex Pilon"]
|
9
|
+
spec.email = ["apilo088@gmail.com"]
|
10
|
+
|
11
|
+
spec.summary = "Generate short, uncrawlable URI"
|
12
|
+
spec.description = "Generate short, uncrawlable URI"
|
13
|
+
spec.homepage = "https://github.com/MadMub/mini-uri"
|
14
|
+
|
15
|
+
spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
16
|
+
spec.bindir = "exe"
|
17
|
+
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
18
|
+
spec.require_paths = ["lib"]
|
19
|
+
|
20
|
+
spec.add_development_dependency "bundler", "~> 1.12"
|
21
|
+
spec.add_development_dependency "rake", "~> 10.0"
|
22
|
+
spec.add_development_dependency "rspec", "~> 3.0"
|
23
|
+
spec.add_dependency "base62", "~> 1.0"
|
24
|
+
end
|
metadata
ADDED
@@ -0,0 +1,106 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: mini_uri
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.9.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Alex Pilon
|
8
|
+
autorequire:
|
9
|
+
bindir: exe
|
10
|
+
cert_chain: []
|
11
|
+
date: 2016-08-03 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.12'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.12'
|
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
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: base62
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '1.0'
|
62
|
+
type: :runtime
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '1.0'
|
69
|
+
description: Generate short, uncrawlable URI
|
70
|
+
email:
|
71
|
+
- apilo088@gmail.com
|
72
|
+
executables: []
|
73
|
+
extensions: []
|
74
|
+
extra_rdoc_files: []
|
75
|
+
files:
|
76
|
+
- ".gitignore"
|
77
|
+
- Gemfile
|
78
|
+
- License.md
|
79
|
+
- README.md
|
80
|
+
- Rakefile
|
81
|
+
- lib/mini_uri.rb
|
82
|
+
- mini_uri.gemspec
|
83
|
+
homepage: https://github.com/MadMub/mini-uri
|
84
|
+
licenses: []
|
85
|
+
metadata: {}
|
86
|
+
post_install_message:
|
87
|
+
rdoc_options: []
|
88
|
+
require_paths:
|
89
|
+
- lib
|
90
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
91
|
+
requirements:
|
92
|
+
- - ">="
|
93
|
+
- !ruby/object:Gem::Version
|
94
|
+
version: '0'
|
95
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
96
|
+
requirements:
|
97
|
+
- - ">="
|
98
|
+
- !ruby/object:Gem::Version
|
99
|
+
version: '0'
|
100
|
+
requirements: []
|
101
|
+
rubyforge_project:
|
102
|
+
rubygems_version: 2.2.3
|
103
|
+
signing_key:
|
104
|
+
specification_version: 4
|
105
|
+
summary: Generate short, uncrawlable URI
|
106
|
+
test_files: []
|