Class: SimpleStructuredSecrets

Inherits:
Object
  • Object
show all
Includes:
Base62
Defined in:
lib/sssecrets.rb

Overview

Simple Structured Secrets aims to implement GitHub’s authentication token format as faithfully as possible. You can learn more about the design and properties of these tokens at the following link: github.blog/2021-04-05-behind-githubs-new-authentication-token-formats/

Defined Under Namespace

Classes: Error

Constant Summary

Constants included from Base62

Base62::BASE, Base62::KEYS, Base62::KEYS_HASH

Instance Attribute Summary collapse

Instance Method Summary collapse

Methods included from Base62

#base62_decode, #base62_encode

Constructor Details

#initialize(org, type) ⇒ SimpleStructuredSecrets

Returns a new instance of SimpleStructuredSecrets.



53
54
55
56
57
58
# File 'lib/sssecrets.rb', line 53

def initialize(org, type)
  raise "Prefix is too long." if org.length + type.length > 10

  @org = org
  @type = type
end

Instance Attribute Details

#orgObject

Returns the value of attribute org.



51
52
53
# File 'lib/sssecrets.rb', line 51

def org
  @org
end

#typeObject

Returns the value of attribute type.



51
52
53
# File 'lib/sssecrets.rb', line 51

def type
  @type
end

Instance Method Details

#calc_checksum(secret) ⇒ Object

Calculate the base62-encoded CRC32 checksum for a given input string. When necessary, this value will be left-padded with 0 to ensure it’s always 6 characters long.

Example:

>> SimpleStructuredSecrets.calc_checksum("GUkLdIZV8xnQQZobkuynSyyPkcweVm")
=> "14nosQ"

Arguments:

secret: (String)


80
81
82
# File 'lib/sssecrets.rb', line 80

def calc_checksum(secret)
  base62_encode(Zlib.crc32(secret)).ljust(6, "0")
end

#generateObject

Generate a Simple Structured Secret token.

Example:

>> SimpleStructuredSecret.generate
=> "tk_GUkLdIZV8xnQQZobkuynSyyPkcweVm14nosQ"


65
66
67
68
# File 'lib/sssecrets.rb', line 65

def generate
  random = base62_encode(SecureRandom.rand(10**60)).to_s[0...30]
  "#{@org}#{@type}_#{random}#{calc_checksum(random)}"
end

#generate_header(str) ⇒ Object

Append a Simple Structured Secret header to a provided string. This is useful in cases where you’d like to realize the secret scanning benefits of SSS with other token formats.

Example:

>> SimpleStructuredSecrets.generate_header("5be426ee126b88f9587bbbe767a7592c")
=> "tk_1e6YXE_5be426ee126b88f9587bbbe767a7592c"

Arguments:

str: (String)


110
111
112
# File 'lib/sssecrets.rb', line 110

def generate_header(str)
  "#{@org}#{@type}_#{calc_checksum(str)}_#{str}"
end

#validate(secret) ⇒ Object

Validate a given Simple Structured Secret token. Note that this only indicates whether a given token is in the correct form and has a valid checksum. You will still need to implement your own logic for checking the validity of tokens you’ve issued.

Example:

>> SimpleStructuredSecrets.validate("tk_GUkLdIZV8xnQQZobkuynSyyPkcweVm14nosQ")
=> true

Arguments:

secret: (String)


95
96
97
98
# File 'lib/sssecrets.rb', line 95

def validate(secret)
  random = /(?<=_)[A-Za-z0-9]{30}/.match(secret).to_s
  calc_checksum(random) == secret.chars.last(6).join
end

#validate_header(str) ⇒ Object

Validate a Simple Structured Secret header for a given string.

Example:

>> SimpleStructuredSecrets.validate_header("tk_1e6YXE_5be426ee126b88f9587bbbe767a7592c")
=> true

Arguments:

str: (String)


122
123
124
125
# File 'lib/sssecrets.rb', line 122

def validate_header(str)
  matches = /(?<prefix>.*)_(?<checksum>[A-Za-z0-9]{6})_(?<string>.*)/.match(str)
  calc_checksum(matches["string"]) == matches["checksum"]
end