bcrypt 3.1.13 → 3.1.18
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/.github/workflows/ruby.yml +59 -0
- data/.gitignore +1 -0
- data/CHANGELOG +86 -67
- data/README.md +4 -6
- data/Rakefile +2 -0
- data/bcrypt.gemspec +3 -3
- data/ext/mri/bcrypt_ext.c +70 -18
- data/ext/mri/crypt_blowfish.c +6 -10
- data/ext/mri/crypt_gensalt.c +1 -1
- data/ext/mri/crypt_gensalt.h +1 -1
- data/ext/mri/wrapper.c +4 -1
- data/ext/mri/x86.S +1 -1
- data/lib/bcrypt/engine.rb +17 -6
- data/lib/bcrypt/password.rb +13 -3
- data/spec/bcrypt/engine_spec.rb +31 -2
- data/spec/bcrypt/password_spec.rb +9 -2
- metadata +15 -18
- data/.travis.yml +0 -17
- data/Gemfile.lock +0 -37
- data/appveyor.yml +0 -50
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ba8b7b14c18d5ad7f8dcd58b2e719925695a8af445b232d50fc21695b3cd4200
|
4
|
+
data.tar.gz: a3a566bb869dcc9001dbeae8041595152444596253d152c9a374ce9c1503d817
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 9e21ae566338f46280af6576c42b54d6dfe9e75619c35a72b87f6401bef689be8526b3385a556f332c28d9a939ca7cd4f2104ef1483f4cc24d144ba837b69af4
|
7
|
+
data.tar.gz: 1c2e714911083b8aa457d9d16c5dd084acd6610e67a4f2c489ec137b1c503f2753d4a2c98e06446bc7771caec176b7b24a207f7395541e32c31268c8d8773551
|
@@ -0,0 +1,59 @@
|
|
1
|
+
name: Test Suite
|
2
|
+
|
3
|
+
# Run against all commits and pull requests.
|
4
|
+
on: [ push, pull_request ]
|
5
|
+
|
6
|
+
jobs:
|
7
|
+
test_matrix:
|
8
|
+
|
9
|
+
strategy:
|
10
|
+
fail-fast: false
|
11
|
+
matrix:
|
12
|
+
os:
|
13
|
+
- ubuntu
|
14
|
+
- macos
|
15
|
+
- windows
|
16
|
+
ruby:
|
17
|
+
- 2.1
|
18
|
+
- 2.2
|
19
|
+
- 2.3
|
20
|
+
- 2.4
|
21
|
+
- 2.5
|
22
|
+
- 2.6
|
23
|
+
- 2.7
|
24
|
+
- '3.0'
|
25
|
+
- 3.1
|
26
|
+
- head
|
27
|
+
- jruby
|
28
|
+
- jruby-head
|
29
|
+
- truffleruby
|
30
|
+
- truffleruby-head
|
31
|
+
- mingw
|
32
|
+
exclude:
|
33
|
+
- { os: ubuntu, ruby: mingw }
|
34
|
+
- { os: macos, ruby: mingw }
|
35
|
+
- { os: windows, ruby: truffleruby }
|
36
|
+
- { os: windows, ruby: truffleruby-head }
|
37
|
+
|
38
|
+
runs-on: ${{ matrix.os }}-latest
|
39
|
+
|
40
|
+
steps:
|
41
|
+
- uses: actions/checkout@v2
|
42
|
+
- name: Set up Ruby
|
43
|
+
uses: ruby/setup-ruby@v1
|
44
|
+
with:
|
45
|
+
ruby-version: ${{ matrix.ruby }}
|
46
|
+
bundler-cache: true
|
47
|
+
env:
|
48
|
+
JAVA_OPTS: -Djdk.io.File.enableADS=true
|
49
|
+
- name: Run tests
|
50
|
+
run: bundle exec rake default
|
51
|
+
env:
|
52
|
+
JAVA_OPTS: -Djdk.io.File.enableADS=true
|
53
|
+
|
54
|
+
finish:
|
55
|
+
runs-on: ubuntu-latest
|
56
|
+
needs: [ test_matrix ]
|
57
|
+
steps:
|
58
|
+
- name: Wait for status checks
|
59
|
+
run: echo "All Green!"
|
data/.gitignore
CHANGED
data/CHANGELOG
CHANGED
@@ -1,94 +1,113 @@
|
|
1
|
-
1.
|
2
|
-
|
1
|
+
3.1.18 May 16 2022
|
2
|
+
- Unlock GVL when calculating hashes and salts [GH #260]
|
3
|
+
- Fix compilation warnings in `ext/mri/bcrypt_ext.c` [GH #261]
|
3
4
|
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
- Added validation of secrets -- nil is not healthy.
|
5
|
+
3.1.17 Mar 14 2022
|
6
|
+
- Fix regex in validators to use \A and \z instead of ^ and $ [GH #121]
|
7
|
+
- Truncate secrets greater than 72 bytes in hash_secret [GH #255]
|
8
|
+
- Assorted test and doc improvements
|
9
9
|
|
10
|
-
|
11
|
-
|
12
|
-
- Fixed crashes when hashing weird values (e.g., false, etc.)
|
10
|
+
3.1.16 Sep 3 2020
|
11
|
+
- Fix compilation on FreeBSD. [GH #234]
|
13
12
|
|
14
|
-
|
15
|
-
|
16
|
-
- Fixed Solaris compatibility [Jeremy LaTrasse, Twitter crew]
|
13
|
+
3.1.15 July 21 2020
|
14
|
+
- Remove GVL optimization. Apparently it breaks things [GH #230]
|
17
15
|
|
18
|
-
|
19
|
-
|
20
|
-
- Changed BCrypt::Engine.hash to BCrypt::Engine.hash_secret to avoid Merb
|
21
|
-
sorting issues. [Lee Pope]
|
16
|
+
3.1.14 July 21 2020
|
17
|
+
- Start calibration from the minimum cost supported by the algorithm [GH #206 by @sergey-alekseev]
|
22
18
|
|
23
|
-
|
24
|
-
-
|
25
|
-
-
|
19
|
+
3.1.13 May 31 2019
|
20
|
+
- No longer include compiled binaries for Windows. See GH #173.
|
21
|
+
- Update C and Java implementations to latest versions [GH #182 by @fonica]
|
22
|
+
- Bump default cost to 12 [GH #181 by @bdewater]
|
23
|
+
- Remove explicit support for Rubies 1.8 and 1.9
|
24
|
+
- Define SKIP_GNU token when building extension (Fixes FreeBSD >= 12) [GH #189 by @adam12]
|
26
25
|
|
27
|
-
|
28
|
-
-
|
26
|
+
3.1.12 May 16 2018
|
27
|
+
- Add support for Ruby 2.3, 2.4, and 2.5 in compiled Windows binaries
|
28
|
+
- Fix compatibility with libxcrypt - Fixes hash errors in Fedora 28 and Ubuntu 20 [GH #164 by @besser82]
|
29
29
|
|
30
|
-
|
31
|
-
-
|
32
|
-
- Ruby 1.9 compatibility fixes. [Hongli Lai]
|
33
|
-
- JRuby support, using Damien Miller's jBCrypt. [Hongli Lai]
|
34
|
-
- Ruby 1.9 GIL releasing for high-cost hashes. [Hongli Lai]
|
30
|
+
3.1.11 Mar 06 2016
|
31
|
+
- Add support for Ruby 2.2 in compiled Windows binaries
|
35
32
|
|
36
|
-
|
37
|
-
-
|
33
|
+
3.1.10 Jan 28 2015
|
34
|
+
- Fix issue with dumping a BCrypt::Password instance to YAML in Ruby 2.2 [GH #107 by @mattwildig]
|
38
35
|
|
39
|
-
|
40
|
-
-
|
36
|
+
3.1.9 Oct 23 2014
|
37
|
+
- Rebuild corrupt binaries
|
41
38
|
|
42
|
-
3.
|
43
|
-
-
|
44
|
-
- License changed to MIT
|
39
|
+
3.1.8 Oct 23 2014
|
40
|
+
- Add support for Ruby 2.1 in compiled Windows binaries [GH #102]
|
45
41
|
|
46
|
-
3.
|
47
|
-
-
|
42
|
+
3.1.7 Feb 24 2014
|
43
|
+
- Rebuild corrupt Java binary version of gem [GH #90]
|
44
|
+
- The 2.1 support for Windows binaries alleged in 3.1.3 was a lie -- documentation removed
|
45
|
+
|
46
|
+
3.1.6 Feb 21 2014
|
47
|
+
- Dummy version of "bcrypt-ruby" needed a couple version bumps to fix some
|
48
|
+
bugs. It felt wrong to have that at a higher version than the real gem, so
|
49
|
+
the real gem is getting bumped to 3.1.6.
|
50
|
+
|
51
|
+
3.1.3 Feb 21 2014
|
52
|
+
- Add support for Ruby 2.1 in compiled Windows binaries
|
53
|
+
- Rename gem from "bcrypt-ruby" to just "bcrypt". [GH #86 by @sferik]
|
54
|
+
|
55
|
+
3.1.2 Aug 26 2013
|
56
|
+
- Add support for Ruby 1.8 and 2.0 (in addition to 1.9) in compiled Windows binaries
|
57
|
+
- Add support for 64-bit Windows
|
58
|
+
|
59
|
+
3.1.1 Jul 10 2013
|
60
|
+
- Remove support for Ruby 1.8 in compiled win32 binaries
|
48
61
|
|
49
62
|
3.1.0 May 07 2013
|
50
63
|
- Add BCrypt::Password.valid_hash?(str) to check if a string is a valid bcrypt password hash
|
51
64
|
- BCrypt::Password cost should be set to DEFAULT_COST if nil
|
52
65
|
- Add BCrypt::Engine.cost attribute for getting/setting a default cost externally
|
53
66
|
|
54
|
-
3.
|
55
|
-
-
|
67
|
+
3.0.1 Sep 12 2011
|
68
|
+
- create raises an exception if the cost is higher than 31. GH #27
|
56
69
|
|
57
|
-
3.
|
58
|
-
-
|
59
|
-
-
|
70
|
+
3.0.0 Aug 24 2011
|
71
|
+
- Bcrypt C implementation replaced with a public domain implementation.
|
72
|
+
- License changed to MIT
|
60
73
|
|
61
|
-
|
62
|
-
-
|
63
|
-
- Rename gem from "bcrypt-ruby" to just "bcrypt". [GH #86 by @sferik]
|
74
|
+
2.1.2 Sep 16 2009
|
75
|
+
- Fixed support for Solaris, OpenSolaris.
|
64
76
|
|
65
|
-
|
66
|
-
-
|
67
|
-
bugs. It felt wrong to have that at a higher version than the real gem, so
|
68
|
-
the real gem is getting bumped to 3.1.6.
|
77
|
+
2.1.1 Aug 14 2009
|
78
|
+
- JVM 1.4/1.5 compatibility [Hongli Lai]
|
69
79
|
|
70
|
-
|
71
|
-
-
|
72
|
-
-
|
80
|
+
2.1.0 Aug 12 2009
|
81
|
+
- Improved code coverage, unit tests, and build chain. [Hongli Lai]
|
82
|
+
- Ruby 1.9 compatibility fixes. [Hongli Lai]
|
83
|
+
- JRuby support, using Damien Miller's jBCrypt. [Hongli Lai]
|
84
|
+
- Ruby 1.9 GIL releasing for high-cost hashes. [Hongli Lai]
|
73
85
|
|
74
|
-
|
75
|
-
-
|
86
|
+
2.0.5 Mar 11 2009
|
87
|
+
- Fixed Ruby 1.8.5 compatibility. [Mike Pomraning]
|
76
88
|
|
77
|
-
|
78
|
-
-
|
89
|
+
2.0.4 Mar 09 2009
|
90
|
+
- Added Ruby 1.9 compatibility. [Genki Takiuchi]
|
91
|
+
- Fixed segfaults on some different types of empty strings. [Mike Pomraning]
|
79
92
|
|
80
|
-
|
81
|
-
|
93
|
+
2.0.3 May 07 2008
|
94
|
+
- Made exception classes descend from StandardError, not Exception [Dan42]
|
95
|
+
- Changed BCrypt::Engine.hash to BCrypt::Engine.hash_secret to avoid Merb
|
96
|
+
sorting issues. [Lee Pope]
|
82
97
|
|
83
|
-
|
84
|
-
|
98
|
+
2.0.2 Jun 06 2007
|
99
|
+
- Fixed example code in the README [Winson]
|
100
|
+
- Fixed Solaris compatibility [Jeremy LaTrasse, Twitter crew]
|
85
101
|
|
86
|
-
|
87
|
-
|
88
|
-
|
102
|
+
2.0.1 Mar 09 2007
|
103
|
+
- Fixed load path issues
|
104
|
+
- Fixed crashes when hashing weird values (e.g., false, etc.)
|
89
105
|
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
106
|
+
2.0.0 Mar 07 2007
|
107
|
+
- Removed BCrypt::Password#exactly_equals -- use BCrypt::Password#eql? instead.
|
108
|
+
- Added BCrypt::Password#is_password?.
|
109
|
+
- Refactored out BCrypt::Internals into more useful BCrypt::Engine.
|
110
|
+
- Added validation of secrets -- nil is not healthy.
|
111
|
+
|
112
|
+
1.0.0 Feb 27 2007
|
113
|
+
- Initial release.
|
data/README.md
CHANGED
@@ -2,11 +2,9 @@
|
|
2
2
|
|
3
3
|
An easy way to keep your users' passwords secure.
|
4
4
|
|
5
|
-
* https://github.com/
|
6
|
-
|
7
|
-
[](https://travis-ci.org/codahale/bcrypt-ruby)
|
8
|
-
[](https://ci.appveyor.com/project/TJSchuck35975/bcrypt-ruby)
|
5
|
+
* https://github.com/bcrypt-ruby/bcrypt-ruby/tree/master
|
9
6
|
|
7
|
+
[](https://github.com/bcrypt-ruby/bcrypt-ruby/actions/workflows/ruby.yml)
|
10
8
|
|
11
9
|
## Why you should use `bcrypt()`
|
12
10
|
|
@@ -32,8 +30,8 @@ re-hash those passwords. This vulnerability only affected the JRuby gem.
|
|
32
30
|
The bcrypt gem is available on the following Ruby platforms:
|
33
31
|
|
34
32
|
* JRuby
|
35
|
-
* RubyInstaller 2.0 –
|
36
|
-
* Any 2.0 –
|
33
|
+
* RubyInstaller 2.0 – 3.0 builds on Windows with the DevKit
|
34
|
+
* Any 2.0 – 3.0 Ruby on a BSD/OS X/Linux system with a compiler
|
37
35
|
|
38
36
|
## How to use `bcrypt()` in your Rails application
|
39
37
|
|
data/Rakefile
CHANGED
data/bcrypt.gemspec
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
Gem::Specification.new do |s|
|
2
2
|
s.name = 'bcrypt'
|
3
|
-
s.version = '3.1.
|
3
|
+
s.version = '3.1.18'
|
4
4
|
|
5
5
|
s.summary = "OpenBSD's bcrypt() password hashing algorithm."
|
6
6
|
s.description = <<-EOF
|
@@ -12,7 +12,7 @@ Gem::Specification.new do |s|
|
|
12
12
|
s.files = `git ls-files`.split("\n")
|
13
13
|
s.require_path = 'lib'
|
14
14
|
|
15
|
-
s.add_development_dependency 'rake-compiler', '~>
|
15
|
+
s.add_development_dependency 'rake-compiler', '~> 1.2.0'
|
16
16
|
s.add_development_dependency 'rspec', '>= 3'
|
17
17
|
|
18
18
|
s.rdoc_options += ['--title', 'bcrypt-ruby', '--line-numbers', '--inline-source', '--main', 'README.md']
|
@@ -22,6 +22,6 @@ Gem::Specification.new do |s|
|
|
22
22
|
|
23
23
|
s.authors = ["Coda Hale"]
|
24
24
|
s.email = "coda.hale@gmail.com"
|
25
|
-
s.homepage = "https://github.com/
|
25
|
+
s.homepage = "https://github.com/bcrypt-ruby/bcrypt-ruby"
|
26
26
|
s.license = "MIT"
|
27
27
|
end
|
data/ext/mri/bcrypt_ext.c
CHANGED
@@ -1,53 +1,105 @@
|
|
1
1
|
#include <ruby.h>
|
2
2
|
#include <ow-crypt.h>
|
3
3
|
|
4
|
+
#ifdef HAVE_RUBY_THREAD_H
|
5
|
+
#include <ruby/thread.h>
|
6
|
+
#endif
|
7
|
+
|
4
8
|
static VALUE mBCrypt;
|
5
9
|
static VALUE cBCryptEngine;
|
6
10
|
|
11
|
+
struct bc_salt_args {
|
12
|
+
const char * prefix;
|
13
|
+
unsigned long count;
|
14
|
+
const char * input;
|
15
|
+
int size;
|
16
|
+
};
|
17
|
+
|
18
|
+
static void * bc_salt_nogvl(void * ptr) {
|
19
|
+
struct bc_salt_args * args = ptr;
|
20
|
+
|
21
|
+
return crypt_gensalt_ra(args->prefix, args->count, args->input, args->size);
|
22
|
+
}
|
23
|
+
|
7
24
|
/* Given a logarithmic cost parameter, generates a salt for use with +bc_crypt+.
|
8
25
|
*/
|
9
26
|
static VALUE bc_salt(VALUE self, VALUE prefix, VALUE count, VALUE input) {
|
10
27
|
char * salt;
|
11
28
|
VALUE str_salt;
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
29
|
+
struct bc_salt_args args;
|
30
|
+
|
31
|
+
/* duplicate the parameters for thread safety. If another thread has a
|
32
|
+
* reference to the parameters and mutates them while we are working,
|
33
|
+
* that would be very bad. Duping the strings means that the reference
|
34
|
+
* isn't shared. */
|
35
|
+
prefix = rb_str_new_frozen(prefix);
|
36
|
+
input = rb_str_new_frozen(input);
|
37
|
+
|
38
|
+
args.prefix = StringValueCStr(prefix);
|
39
|
+
args.count = NUM2ULONG(count);
|
40
|
+
args.input = NIL_P(input) ? NULL : StringValuePtr(input);
|
41
|
+
args.size = NIL_P(input) ? 0 : RSTRING_LEN(input);
|
42
|
+
|
43
|
+
#ifdef HAVE_RUBY_THREAD_H
|
44
|
+
salt = rb_thread_call_without_gvl(bc_salt_nogvl, &args, NULL, NULL);
|
45
|
+
#else
|
46
|
+
salt = bc_salt_nogvl((void *)&args);
|
47
|
+
#endif
|
18
48
|
|
19
49
|
if(!salt) return Qnil;
|
20
50
|
|
21
51
|
str_salt = rb_str_new2(salt);
|
22
|
-
|
52
|
+
free(salt);
|
23
53
|
|
24
54
|
return str_salt;
|
25
55
|
}
|
26
56
|
|
57
|
+
struct bc_crypt_args {
|
58
|
+
const char * key;
|
59
|
+
const char * setting;
|
60
|
+
void * data;
|
61
|
+
int size;
|
62
|
+
};
|
63
|
+
|
64
|
+
static void * bc_crypt_nogvl(void * ptr) {
|
65
|
+
struct bc_crypt_args * args = ptr;
|
66
|
+
|
67
|
+
return crypt_ra(args->key, args->setting, &args->data, &args->size);
|
68
|
+
}
|
69
|
+
|
27
70
|
/* Given a secret and a salt, generates a salted hash (which you can then store safely).
|
28
71
|
*/
|
29
72
|
static VALUE bc_crypt(VALUE self, VALUE key, VALUE setting) {
|
30
73
|
char * value;
|
31
|
-
void * data;
|
32
|
-
int size;
|
33
74
|
VALUE out;
|
34
75
|
|
35
|
-
|
36
|
-
size = 0xDEADBEEF;
|
76
|
+
struct bc_crypt_args args;
|
37
77
|
|
38
78
|
if(NIL_P(key) || NIL_P(setting)) return Qnil;
|
39
79
|
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
80
|
+
/* duplicate the parameters for thread safety. If another thread has a
|
81
|
+
* reference to the parameters and mutates them while we are working,
|
82
|
+
* that would be very bad. Duping the strings means that the reference
|
83
|
+
* isn't shared. */
|
84
|
+
key = rb_str_new_frozen(key);
|
85
|
+
setting = rb_str_new_frozen(setting);
|
86
|
+
|
87
|
+
args.data = NULL;
|
88
|
+
args.size = 0xDEADBEEF;
|
89
|
+
args.key = NIL_P(key) ? NULL : StringValueCStr(key);
|
90
|
+
args.setting = NIL_P(setting) ? NULL : StringValueCStr(setting);
|
91
|
+
|
92
|
+
#ifdef HAVE_RUBY_THREAD_H
|
93
|
+
value = rb_thread_call_without_gvl(bc_crypt_nogvl, &args, NULL, NULL);
|
94
|
+
#else
|
95
|
+
value = bc_crypt_nogvl((void *)&args);
|
96
|
+
#endif
|
45
97
|
|
46
|
-
if(!value) return Qnil;
|
98
|
+
if(!value || !args.data) return Qnil;
|
47
99
|
|
48
100
|
out = rb_str_new2(value);
|
49
101
|
|
50
|
-
|
102
|
+
free(args.data);
|
51
103
|
|
52
104
|
return out;
|
53
105
|
}
|
data/ext/mri/crypt_blowfish.c
CHANGED
@@ -361,7 +361,7 @@ static BF_ctx BF_init_state = {
|
|
361
361
|
}
|
362
362
|
};
|
363
363
|
|
364
|
-
static unsigned char BF_itoa64[64 + 1] =
|
364
|
+
static const unsigned char BF_itoa64[64 + 1] =
|
365
365
|
"./ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
|
366
366
|
|
367
367
|
static unsigned char BF_atoi64[0x60] = {
|
@@ -387,9 +387,8 @@ static int BF_decode(BF_word *dst, const char *src, int size)
|
|
387
387
|
unsigned char *dptr = (unsigned char *)dst;
|
388
388
|
unsigned char *end = dptr + size;
|
389
389
|
const unsigned char *sptr = (const unsigned char *)src;
|
390
|
-
unsigned int tmp, c1, c2, c3, c4;
|
391
|
-
|
392
390
|
do {
|
391
|
+
unsigned int tmp, c1, c2, c3, c4;
|
393
392
|
BF_safe_atoi64(c1, *sptr++);
|
394
393
|
BF_safe_atoi64(c2, *sptr++);
|
395
394
|
*dptr++ = (c1 << 2) | ((c2 & 0x30) >> 4);
|
@@ -402,7 +401,6 @@ static int BF_decode(BF_word *dst, const char *src, int size)
|
|
402
401
|
BF_safe_atoi64(c4, *sptr++);
|
403
402
|
*dptr++ = ((c3 & 0x03) << 6) | c4;
|
404
403
|
} while (dptr < end);
|
405
|
-
|
406
404
|
return 0;
|
407
405
|
}
|
408
406
|
|
@@ -411,9 +409,8 @@ static void BF_encode(char *dst, const BF_word *src, int size)
|
|
411
409
|
const unsigned char *sptr = (const unsigned char *)src;
|
412
410
|
const unsigned char *end = sptr + size;
|
413
411
|
unsigned char *dptr = (unsigned char *)dst;
|
414
|
-
unsigned int c1, c2;
|
415
|
-
|
416
412
|
do {
|
413
|
+
unsigned int c1, c2;
|
417
414
|
c1 = *sptr++;
|
418
415
|
*dptr++ = BF_itoa64[c1 >> 2];
|
419
416
|
c1 = (c1 & 0x03) << 4;
|
@@ -442,10 +439,9 @@ static void BF_swap(BF_word *x, int count)
|
|
442
439
|
{
|
443
440
|
static int endianness_check = 1;
|
444
441
|
char *is_little_endian = (char *)&endianness_check;
|
445
|
-
BF_word tmp;
|
446
|
-
|
447
442
|
if (*is_little_endian)
|
448
443
|
do {
|
444
|
+
BF_word tmp;
|
449
445
|
tmp = *x;
|
450
446
|
tmp = (tmp << 16) | (tmp >> 16);
|
451
447
|
*x++ = ((tmp & 0x00FF00FF) << 8) | ((tmp >> 8) & 0x00FF00FF);
|
@@ -517,7 +513,7 @@ static void BF_swap(BF_word *x, int count)
|
|
517
513
|
R = L; \
|
518
514
|
L = tmp4 ^ data.ctx.P[BF_N + 1];
|
519
515
|
|
520
|
-
#if BF_ASM
|
516
|
+
#if BF_ASM == 1
|
521
517
|
#define BF_body() \
|
522
518
|
_BF_body_r(&data.ctx);
|
523
519
|
#else
|
@@ -650,7 +646,7 @@ static char *BF_crypt(const char *key, const char *setting,
|
|
650
646
|
char *output, int size,
|
651
647
|
BF_word min)
|
652
648
|
{
|
653
|
-
#if BF_ASM
|
649
|
+
#if BF_ASM == 1
|
654
650
|
extern void _BF_body_r(BF_ctx *ctx);
|
655
651
|
#endif
|
656
652
|
struct {
|
data/ext/mri/crypt_gensalt.c
CHANGED
@@ -28,7 +28,7 @@
|
|
28
28
|
/* Just to make sure the prototypes match the actual definitions */
|
29
29
|
#include "crypt_gensalt.h"
|
30
30
|
|
31
|
-
unsigned char _crypt_itoa64[64 + 1] =
|
31
|
+
const unsigned char _crypt_itoa64[64 + 1] =
|
32
32
|
"./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
|
33
33
|
|
34
34
|
char *_crypt_gensalt_traditional_rn(const char *prefix, unsigned long count,
|
data/ext/mri/crypt_gensalt.h
CHANGED
@@ -17,7 +17,7 @@
|
|
17
17
|
#ifndef _CRYPT_GENSALT_H
|
18
18
|
#define _CRYPT_GENSALT_H
|
19
19
|
|
20
|
-
extern unsigned char _crypt_itoa64[];
|
20
|
+
extern const unsigned char _crypt_itoa64[];
|
21
21
|
extern char *_crypt_gensalt_traditional_rn(const char *prefix,
|
22
22
|
unsigned long count,
|
23
23
|
const char *input, int size, char *output, int output_size);
|
data/ext/mri/wrapper.c
CHANGED
@@ -17,6 +17,9 @@
|
|
17
17
|
#include <stdlib.h>
|
18
18
|
#include <string.h>
|
19
19
|
|
20
|
+
/* Redefine strdup to ruby_strdup in case string.h doesn't export it. */
|
21
|
+
#include <ruby/util.h>
|
22
|
+
|
20
23
|
#include <errno.h>
|
21
24
|
#ifndef __set_errno
|
22
25
|
#define __set_errno(val) errno = (val)
|
@@ -176,7 +179,7 @@ char *crypt_ra(const char *key, const char *setting,
|
|
176
179
|
return _crypt_blowfish_rn(key, setting, (char *)*data, *size);
|
177
180
|
}
|
178
181
|
|
179
|
-
char *crypt_r(const char *key, const char *setting,
|
182
|
+
char *crypt_r(const char *key, const char *setting, struct crypt_data *data)
|
180
183
|
{
|
181
184
|
return _crypt_retval_magic(
|
182
185
|
crypt_rn(key, setting, data, CRYPT_OUTPUT_SIZE),
|
data/ext/mri/x86.S
CHANGED
data/lib/bcrypt/engine.rb
CHANGED
@@ -5,6 +5,16 @@ module BCrypt
|
|
5
5
|
DEFAULT_COST = 12
|
6
6
|
# The minimum cost supported by the algorithm.
|
7
7
|
MIN_COST = 4
|
8
|
+
# The maximum cost supported by the algorithm.
|
9
|
+
MAX_COST = 31
|
10
|
+
# Maximum possible size of bcrypt() secrets.
|
11
|
+
# Older versions of the bcrypt library would truncate passwords longer
|
12
|
+
# than 72 bytes, but newer ones do not. We truncate like the old library for
|
13
|
+
# forward compatibility. This way users upgrading from Ubuntu 18.04 to 20.04
|
14
|
+
# will not have their user passwords invalidated, for example.
|
15
|
+
# A max secret length greater than 255 leads to bcrypt returning nil.
|
16
|
+
# https://github.com/bcrypt-ruby/bcrypt-ruby/issues/225#issuecomment-875908425
|
17
|
+
MAX_SECRET_BYTESIZE = 72
|
8
18
|
# Maximum possible size of bcrypt() salts.
|
9
19
|
MAX_SALT_LENGTH = 16
|
10
20
|
|
@@ -41,14 +51,16 @@ module BCrypt
|
|
41
51
|
end
|
42
52
|
|
43
53
|
# Given a secret and a valid salt (see BCrypt::Engine.generate_salt) calculates
|
44
|
-
# a bcrypt() password hash.
|
54
|
+
# a bcrypt() password hash. Secrets longer than 72 bytes are truncated.
|
45
55
|
def self.hash_secret(secret, salt, _ = nil)
|
46
56
|
if valid_secret?(secret)
|
47
57
|
if valid_salt?(salt)
|
48
58
|
if RUBY_PLATFORM == "java"
|
49
59
|
Java.bcrypt_jruby.BCrypt.hashpw(secret.to_s.to_java_bytes, salt.to_s)
|
50
60
|
else
|
51
|
-
|
61
|
+
secret = secret.to_s
|
62
|
+
secret = secret.byteslice(0, MAX_SECRET_BYTESIZE) if secret && secret.bytesize > MAX_SECRET_BYTESIZE
|
63
|
+
__bc_crypt(secret, salt)
|
52
64
|
end
|
53
65
|
else
|
54
66
|
raise Errors::InvalidSalt.new("invalid salt")
|
@@ -68,8 +80,7 @@ module BCrypt
|
|
68
80
|
if RUBY_PLATFORM == "java"
|
69
81
|
Java.bcrypt_jruby.BCrypt.gensalt(cost)
|
70
82
|
else
|
71
|
-
|
72
|
-
__bc_salt(prefix, cost, OpenSSL::Random.random_bytes(MAX_SALT_LENGTH))
|
83
|
+
__bc_salt("$2a$", cost, OpenSSL::Random.random_bytes(MAX_SALT_LENGTH))
|
73
84
|
end
|
74
85
|
else
|
75
86
|
raise Errors::InvalidCost.new("cost must be numeric and > 0")
|
@@ -78,7 +89,7 @@ module BCrypt
|
|
78
89
|
|
79
90
|
# Returns true if +salt+ is a valid bcrypt() salt, false if not.
|
80
91
|
def self.valid_salt?(salt)
|
81
|
-
!!(salt =~
|
92
|
+
!!(salt =~ /\A\$[0-9a-z]{2,}\$[0-9]{2,}\$[A-Za-z0-9\.\/]{22,}\z/)
|
82
93
|
end
|
83
94
|
|
84
95
|
# Returns true if +secret+ is a valid bcrypt() secret, false if not.
|
@@ -99,7 +110,7 @@ module BCrypt
|
|
99
110
|
# # should take less than 1000ms
|
100
111
|
# BCrypt::Password.create("woo", :cost => 12)
|
101
112
|
def self.calibrate(upper_time_limit_in_ms)
|
102
|
-
|
113
|
+
(BCrypt::Engine::MIN_COST..BCrypt::Engine::MAX_COST-1).each do |i|
|
103
114
|
start_time = Time.now
|
104
115
|
Password.create("testing testing", :cost => i+1)
|
105
116
|
end_time = Time.now - start_time
|
data/lib/bcrypt/password.rb
CHANGED
@@ -42,12 +42,12 @@ module BCrypt
|
|
42
42
|
# @password = BCrypt::Password.create("my secret", :cost => 13)
|
43
43
|
def create(secret, options = {})
|
44
44
|
cost = options[:cost] || BCrypt::Engine.cost
|
45
|
-
raise ArgumentError if cost >
|
45
|
+
raise ArgumentError if cost > BCrypt::Engine::MAX_COST
|
46
46
|
Password.new(BCrypt::Engine.hash_secret(secret, BCrypt::Engine.generate_salt(cost)))
|
47
47
|
end
|
48
48
|
|
49
49
|
def valid_hash?(h)
|
50
|
-
|
50
|
+
/\A\$[0-9a-z]{2}\$[0-9]{2}\$[A-Za-z0-9\.\/]{53}\z/ === h
|
51
51
|
end
|
52
52
|
end
|
53
53
|
|
@@ -62,6 +62,17 @@ module BCrypt
|
|
62
62
|
end
|
63
63
|
|
64
64
|
# Compares a potential secret against the hash. Returns true if the secret is the original secret, false otherwise.
|
65
|
+
#
|
66
|
+
# Comparison edge case/gotcha:
|
67
|
+
#
|
68
|
+
# secret = "my secret"
|
69
|
+
# @password = BCrypt::Password.create(secret)
|
70
|
+
#
|
71
|
+
# @password == secret # => True
|
72
|
+
# @password == @password # => False
|
73
|
+
# @password == @password.to_s # => False
|
74
|
+
# @password.to_s == @password # => True
|
75
|
+
# @password.to_s == @password.to_s # => True
|
65
76
|
def ==(secret)
|
66
77
|
super(BCrypt::Engine.hash_secret(secret, @salt))
|
67
78
|
end
|
@@ -83,5 +94,4 @@ module BCrypt
|
|
83
94
|
return v.to_str, c.to_i, h[0, 29].to_str, mash[-31, 31].to_str
|
84
95
|
end
|
85
96
|
end
|
86
|
-
|
87
97
|
end
|
data/spec/bcrypt/engine_spec.rb
CHANGED
@@ -1,9 +1,23 @@
|
|
1
1
|
require File.expand_path(File.join(File.dirname(__FILE__), "..", "spec_helper"))
|
2
|
+
require 'securerandom'
|
3
|
+
|
4
|
+
describe 'BCrypt::Engine' do
|
5
|
+
describe '.calibrate(upper_time_limit_in_ms)' do
|
6
|
+
context 'a tiny upper time limit provided' do
|
7
|
+
it 'returns a minimum cost supported by the algorithm' do
|
8
|
+
expect(BCrypt::Engine.calibrate(0.001)).to eq(4)
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
2
13
|
|
3
14
|
describe "The BCrypt engine" do
|
4
15
|
specify "should calculate the optimal cost factor to fit in a specific time" do
|
5
|
-
|
6
|
-
|
16
|
+
start_time = Time.now
|
17
|
+
BCrypt::Password.create("testing testing", :cost => BCrypt::Engine::MIN_COST + 1)
|
18
|
+
min_time_ms = (Time.now - start_time) * 1000
|
19
|
+
first = BCrypt::Engine.calibrate(min_time_ms)
|
20
|
+
second = BCrypt::Engine.calibrate(min_time_ms * 4)
|
7
21
|
expect(second).to be > first
|
8
22
|
end
|
9
23
|
end
|
@@ -144,4 +158,19 @@ describe "Generating BCrypt hashes" do
|
|
144
158
|
expect(BCrypt::Engine.hash_secret(secret, salt)).to eql(test_vector)
|
145
159
|
end
|
146
160
|
end
|
161
|
+
|
162
|
+
specify "should truncate long 1-byte character secrets to 72 bytes" do
|
163
|
+
# 'b' as a base triggers the failure at 256 characters, but 'a' does not.
|
164
|
+
too_long_secret = 'b'*(BCrypt::Engine::MAX_SECRET_BYTESIZE + 1)
|
165
|
+
just_right_secret = 'b'*BCrypt::Engine::MAX_SECRET_BYTESIZE
|
166
|
+
expect(BCrypt::Engine.hash_secret(too_long_secret, @salt)).to eq(BCrypt::Engine.hash_secret(just_right_secret, @salt))
|
167
|
+
end
|
168
|
+
|
169
|
+
specify "should truncate long multi-byte character secrets to 72 bytes" do
|
170
|
+
# 256 times causes bcrypt to return nil for libxcrypt > 4.4.18-4.
|
171
|
+
too_long_secret = '𐐷'*256
|
172
|
+
# 𐐷 takes 4 bytes in UTF-8. 18 times is 72 bytes
|
173
|
+
just_right_secret = '𐐷'*18
|
174
|
+
expect(BCrypt::Engine.hash_secret(too_long_secret, @salt)).to eq(BCrypt::Engine.hash_secret(just_right_secret, @salt))
|
175
|
+
end
|
147
176
|
end
|
@@ -1,4 +1,5 @@
|
|
1
1
|
require File.expand_path(File.join(File.dirname(__FILE__), "..", "spec_helper"))
|
2
|
+
require 'securerandom'
|
2
3
|
|
3
4
|
describe "Creating a hashed password" do
|
4
5
|
|
@@ -26,6 +27,10 @@ describe "Creating a hashed password" do
|
|
26
27
|
expect { BCrypt::Password.create( "" ) }.not_to raise_error
|
27
28
|
expect { BCrypt::Password.create( String.new ) }.not_to raise_error
|
28
29
|
end
|
30
|
+
|
31
|
+
specify "should tolerate very long string secrets" do
|
32
|
+
expect { BCrypt::Password.create("abcd"*1024) }.not_to raise_error
|
33
|
+
end
|
29
34
|
end
|
30
35
|
|
31
36
|
describe "Reading a hashed password" do
|
@@ -108,6 +113,7 @@ end
|
|
108
113
|
describe "Validating a generated salt" do
|
109
114
|
specify "should not accept an invalid salt" do
|
110
115
|
expect(BCrypt::Engine.valid_salt?("invalid")).to eq(false)
|
116
|
+
expect(BCrypt::Engine.valid_salt?("invalid\n#{BCrypt::Engine.generate_salt}\ninvalid")).to eq(false)
|
111
117
|
end
|
112
118
|
specify "should accept a valid salt" do
|
113
119
|
expect(BCrypt::Engine.valid_salt?(BCrypt::Engine.generate_salt)).to eq(true)
|
@@ -116,9 +122,10 @@ end
|
|
116
122
|
|
117
123
|
describe "Validating a password hash" do
|
118
124
|
specify "should not accept an invalid password" do
|
119
|
-
expect(BCrypt::Password.valid_hash?("i_am_so_not_valid")).to
|
125
|
+
expect(BCrypt::Password.valid_hash?("i_am_so_not_valid")).to be(false)
|
126
|
+
expect(BCrypt::Password.valid_hash?("invalid\n#{BCrypt::Password.create "i_am_so_valid"}\ninvalid")).to be(false)
|
120
127
|
end
|
121
128
|
specify "should accept a valid password" do
|
122
|
-
expect(BCrypt::Password.valid_hash?(BCrypt::Password.create "i_am_so_valid")).to
|
129
|
+
expect(BCrypt::Password.valid_hash?(BCrypt::Password.create "i_am_so_valid")).to be(true)
|
123
130
|
end
|
124
131
|
end
|
metadata
CHANGED
@@ -1,38 +1,38 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: bcrypt
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 3.1.
|
4
|
+
version: 3.1.18
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Coda Hale
|
8
|
-
autorequire:
|
8
|
+
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2022-05-16 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
|
+
name: rake-compiler
|
14
15
|
requirement: !ruby/object:Gem::Requirement
|
15
16
|
requirements:
|
16
17
|
- - "~>"
|
17
18
|
- !ruby/object:Gem::Version
|
18
|
-
version:
|
19
|
-
name: rake-compiler
|
20
|
-
prerelease: false
|
19
|
+
version: 1.2.0
|
21
20
|
type: :development
|
21
|
+
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
24
|
- - "~>"
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version:
|
26
|
+
version: 1.2.0
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
|
+
name: rspec
|
28
29
|
requirement: !ruby/object:Gem::Requirement
|
29
30
|
requirements:
|
30
31
|
- - ">="
|
31
32
|
- !ruby/object:Gem::Version
|
32
33
|
version: '3'
|
33
|
-
name: rspec
|
34
|
-
prerelease: false
|
35
34
|
type: :development
|
35
|
+
prerelease: false
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
38
|
- - ">="
|
@@ -50,21 +50,19 @@ extra_rdoc_files:
|
|
50
50
|
- README.md
|
51
51
|
- COPYING
|
52
52
|
- CHANGELOG
|
53
|
-
- lib/bcrypt.rb
|
54
53
|
- lib/bcrypt/password.rb
|
55
54
|
- lib/bcrypt/engine.rb
|
56
55
|
- lib/bcrypt/error.rb
|
56
|
+
- lib/bcrypt.rb
|
57
57
|
files:
|
58
|
+
- ".github/workflows/ruby.yml"
|
58
59
|
- ".gitignore"
|
59
60
|
- ".rspec"
|
60
|
-
- ".travis.yml"
|
61
61
|
- CHANGELOG
|
62
62
|
- COPYING
|
63
63
|
- Gemfile
|
64
|
-
- Gemfile.lock
|
65
64
|
- README.md
|
66
65
|
- Rakefile
|
67
|
-
- appveyor.yml
|
68
66
|
- bcrypt.gemspec
|
69
67
|
- ext/jruby/bcrypt_jruby/BCrypt.java
|
70
68
|
- ext/mri/bcrypt_ext.c
|
@@ -87,11 +85,11 @@ files:
|
|
87
85
|
- spec/bcrypt/error_spec.rb
|
88
86
|
- spec/bcrypt/password_spec.rb
|
89
87
|
- spec/spec_helper.rb
|
90
|
-
homepage: https://github.com/
|
88
|
+
homepage: https://github.com/bcrypt-ruby/bcrypt-ruby
|
91
89
|
licenses:
|
92
90
|
- MIT
|
93
91
|
metadata: {}
|
94
|
-
post_install_message:
|
92
|
+
post_install_message:
|
95
93
|
rdoc_options:
|
96
94
|
- "--title"
|
97
95
|
- bcrypt-ruby
|
@@ -112,9 +110,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
112
110
|
- !ruby/object:Gem::Version
|
113
111
|
version: '0'
|
114
112
|
requirements: []
|
115
|
-
|
116
|
-
|
117
|
-
signing_key:
|
113
|
+
rubygems_version: 3.1.4
|
114
|
+
signing_key:
|
118
115
|
specification_version: 4
|
119
116
|
summary: OpenBSD's bcrypt() password hashing algorithm.
|
120
117
|
test_files: []
|
data/.travis.yml
DELETED
@@ -1,17 +0,0 @@
|
|
1
|
-
language: ruby
|
2
|
-
before_install:
|
3
|
-
- "echo 'gem: --no-rdoc --no-ri' > ~/.gemrc"
|
4
|
-
- gem update --system 2.7.8
|
5
|
-
- gem install bundler -v 1.17.3
|
6
|
-
rvm:
|
7
|
-
- 2.0
|
8
|
-
- 2.1
|
9
|
-
- 2.2
|
10
|
-
- 2.3
|
11
|
-
- 2.4
|
12
|
-
- 2.5
|
13
|
-
- 2.6
|
14
|
-
- ruby-head
|
15
|
-
- jruby-head
|
16
|
-
- rbx-3
|
17
|
-
script: bundle exec rake
|
data/Gemfile.lock
DELETED
@@ -1,37 +0,0 @@
|
|
1
|
-
PATH
|
2
|
-
remote: .
|
3
|
-
specs:
|
4
|
-
bcrypt (3.1.13)
|
5
|
-
|
6
|
-
GEM
|
7
|
-
remote: https://rubygems.org/
|
8
|
-
specs:
|
9
|
-
diff-lcs (1.3)
|
10
|
-
rake (12.3.2)
|
11
|
-
rake-compiler (0.9.9)
|
12
|
-
rake
|
13
|
-
rspec (3.8.0)
|
14
|
-
rspec-core (~> 3.8.0)
|
15
|
-
rspec-expectations (~> 3.8.0)
|
16
|
-
rspec-mocks (~> 3.8.0)
|
17
|
-
rspec-core (3.8.0)
|
18
|
-
rspec-support (~> 3.8.0)
|
19
|
-
rspec-expectations (3.8.3)
|
20
|
-
diff-lcs (>= 1.2.0, < 2.0)
|
21
|
-
rspec-support (~> 3.8.0)
|
22
|
-
rspec-mocks (3.8.0)
|
23
|
-
diff-lcs (>= 1.2.0, < 2.0)
|
24
|
-
rspec-support (~> 3.8.0)
|
25
|
-
rspec-support (3.8.0)
|
26
|
-
|
27
|
-
PLATFORMS
|
28
|
-
java
|
29
|
-
ruby
|
30
|
-
|
31
|
-
DEPENDENCIES
|
32
|
-
bcrypt!
|
33
|
-
rake-compiler (~> 0.9.2)
|
34
|
-
rspec (>= 3)
|
35
|
-
|
36
|
-
BUNDLED WITH
|
37
|
-
1.16.1
|
data/appveyor.yml
DELETED
@@ -1,50 +0,0 @@
|
|
1
|
-
version: "{branch}-{build}"
|
2
|
-
build: off
|
3
|
-
clone_depth: 1
|
4
|
-
|
5
|
-
init:
|
6
|
-
# Install Ruby head
|
7
|
-
- if %RUBY_VERSION%==head (
|
8
|
-
appveyor DownloadFile https://github.com/oneclick/rubyinstaller2/releases/download/rubyinstaller-head/rubyinstaller-head-x86.exe -FileName C:\head_x86.exe &
|
9
|
-
C:\head_x86.exe /verysilent /dir=C:\Ruby%RUBY_VERSION%
|
10
|
-
)
|
11
|
-
- if %RUBY_VERSION%==head-x64 (
|
12
|
-
appveyor DownloadFile https://github.com/oneclick/rubyinstaller2/releases/download/rubyinstaller-head/rubyinstaller-head-x64.exe -FileName C:\head_x64.exe &
|
13
|
-
C:\head_x64.exe /verysilent /dir=C:\Ruby%RUBY_VERSION%
|
14
|
-
)
|
15
|
-
|
16
|
-
# Add Ruby to the path
|
17
|
-
- set PATH=C:\Ruby%RUBY_VERSION%\bin;%PATH%
|
18
|
-
|
19
|
-
environment:
|
20
|
-
matrix:
|
21
|
-
- RUBY_VERSION: "head"
|
22
|
-
- RUBY_VERSION: "head-x64"
|
23
|
-
- RUBY_VERSION: "25"
|
24
|
-
- RUBY_VERSION: "25-x64"
|
25
|
-
- RUBY_VERSION: "24"
|
26
|
-
- RUBY_VERSION: "24-x64"
|
27
|
-
- RUBY_VERSION: "23"
|
28
|
-
- RUBY_VERSION: "23-x64"
|
29
|
-
- RUBY_VERSION: "22"
|
30
|
-
- RUBY_VERSION: "22-x64"
|
31
|
-
- RUBY_VERSION: "21"
|
32
|
-
- RUBY_VERSION: "21-x64"
|
33
|
-
- RUBY_VERSION: "200"
|
34
|
-
- RUBY_VERSION: "200-x64"
|
35
|
-
|
36
|
-
install:
|
37
|
-
- ps: "Set-Content -Value 'gem: --no-ri --no-rdoc ' -Path C:\\ProgramData\\gemrc"
|
38
|
-
- if %RUBY_VERSION%==head ( gem install bundler -v'< 2' )
|
39
|
-
- if %RUBY_VERSION%==head-x64 ( gem install bundler -v'< 2' )
|
40
|
-
- bundle install
|
41
|
-
|
42
|
-
before_build:
|
43
|
-
- ruby -v
|
44
|
-
- gem -v
|
45
|
-
|
46
|
-
build_script:
|
47
|
-
- bundle exec rake compile -rdevkit
|
48
|
-
|
49
|
-
test_script:
|
50
|
-
- bundle exec rake spec
|