truelayer-signing 0.1.0

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.
Files changed (92) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +14 -0
  3. data/LICENSE-APACHE +176 -0
  4. data/LICENSE-MIT +21 -0
  5. data/README.md +82 -0
  6. data/Rakefile +8 -0
  7. data/doc/CHANGELOG_md.html +132 -0
  8. data/doc/JWT/Decode.html +97 -0
  9. data/doc/JWT/Encode.html +97 -0
  10. data/doc/JWT/JWK/EC.html +169 -0
  11. data/doc/JWT/JWK.html +91 -0
  12. data/doc/JWT.html +95 -0
  13. data/doc/LICENSE-APACHE.html +177 -0
  14. data/doc/LICENSE-MIT.html +105 -0
  15. data/doc/README_md.html +197 -0
  16. data/doc/Rakefile.html +106 -0
  17. data/doc/TrueLayerSigning/Config.html +211 -0
  18. data/doc/TrueLayerSigning/Error.html +97 -0
  19. data/doc/TrueLayerSigning/JwsBase.html +317 -0
  20. data/doc/TrueLayerSigning/JwsHeader.html +268 -0
  21. data/doc/TrueLayerSigning/Signer.html +186 -0
  22. data/doc/TrueLayerSigning/Verifier.html +327 -0
  23. data/doc/TrueLayerSigning.html +226 -0
  24. data/doc/TrueLayerSigningExamples.html +217 -0
  25. data/doc/created.rid +21 -0
  26. data/doc/css/fonts.css +167 -0
  27. data/doc/css/rdoc.css +662 -0
  28. data/doc/examples/sign-request/Gemfile.html +99 -0
  29. data/doc/examples/sign-request/Gemfile_lock.html +143 -0
  30. data/doc/examples/sign-request/README_md.html +138 -0
  31. data/doc/examples/webhook-server/Gemfile.html +99 -0
  32. data/doc/examples/webhook-server/Gemfile_lock.html +142 -0
  33. data/doc/examples/webhook-server/README_md.html +139 -0
  34. data/doc/fonts/Lato-Light.ttf +0 -0
  35. data/doc/fonts/Lato-LightItalic.ttf +0 -0
  36. data/doc/fonts/Lato-Regular.ttf +0 -0
  37. data/doc/fonts/Lato-RegularItalic.ttf +0 -0
  38. data/doc/fonts/SourceCodePro-Bold.ttf +0 -0
  39. data/doc/fonts/SourceCodePro-Regular.ttf +0 -0
  40. data/doc/images/add.png +0 -0
  41. data/doc/images/arrow_up.png +0 -0
  42. data/doc/images/brick.png +0 -0
  43. data/doc/images/brick_link.png +0 -0
  44. data/doc/images/bug.png +0 -0
  45. data/doc/images/bullet_black.png +0 -0
  46. data/doc/images/bullet_toggle_minus.png +0 -0
  47. data/doc/images/bullet_toggle_plus.png +0 -0
  48. data/doc/images/date.png +0 -0
  49. data/doc/images/delete.png +0 -0
  50. data/doc/images/find.png +0 -0
  51. data/doc/images/loadingAnimation.gif +0 -0
  52. data/doc/images/macFFBgHack.png +0 -0
  53. data/doc/images/package.png +0 -0
  54. data/doc/images/page_green.png +0 -0
  55. data/doc/images/page_white_text.png +0 -0
  56. data/doc/images/page_white_width.png +0 -0
  57. data/doc/images/plugin.png +0 -0
  58. data/doc/images/ruby.png +0 -0
  59. data/doc/images/tag_blue.png +0 -0
  60. data/doc/images/tag_green.png +0 -0
  61. data/doc/images/transparent.png +0 -0
  62. data/doc/images/wrench.png +0 -0
  63. data/doc/images/wrench_orange.png +0 -0
  64. data/doc/images/zoom.png +0 -0
  65. data/doc/index.html +118 -0
  66. data/doc/js/darkfish.js +84 -0
  67. data/doc/js/navigation.js +105 -0
  68. data/doc/js/navigation.js.gz +0 -0
  69. data/doc/js/search.js +110 -0
  70. data/doc/js/search_index.js +1 -0
  71. data/doc/js/search_index.js.gz +0 -0
  72. data/doc/js/searcher.js +229 -0
  73. data/doc/js/searcher.js.gz +0 -0
  74. data/doc/table_of_contents.html +269 -0
  75. data/examples/sign-request/Gemfile +4 -0
  76. data/examples/sign-request/Gemfile.lock +41 -0
  77. data/examples/sign-request/README.md +27 -0
  78. data/examples/sign-request/main.rb +46 -0
  79. data/examples/webhook-server/Gemfile +3 -0
  80. data/examples/webhook-server/Gemfile.lock +15 -0
  81. data/examples/webhook-server/README.md +30 -0
  82. data/examples/webhook-server/main.rb +98 -0
  83. data/lib/truelayer-signing/config.rb +21 -0
  84. data/lib/truelayer-signing/errors.rb +3 -0
  85. data/lib/truelayer-signing/jwt.rb +20 -0
  86. data/lib/truelayer-signing/signer.rb +34 -0
  87. data/lib/truelayer-signing/utils.rb +90 -0
  88. data/lib/truelayer-signing/verifier.rb +76 -0
  89. data/lib/truelayer-signing.rb +35 -0
  90. data/test/test-truelayer-signing.rb +372 -0
  91. data/truelayer-signing.gemspec +25 -0
  92. metadata +151 -0
Binary file
@@ -0,0 +1,229 @@
1
+ Searcher = function(data) {
2
+ this.data = data;
3
+ this.handlers = [];
4
+ }
5
+
6
+ Searcher.prototype = new function() {
7
+ // search is performed in chunks of 1000 for non-blocking user input
8
+ var CHUNK_SIZE = 1000;
9
+ // do not try to find more than 100 results
10
+ var MAX_RESULTS = 100;
11
+ var huid = 1;
12
+ var suid = 1;
13
+ var runs = 0;
14
+
15
+ this.find = function(query) {
16
+ var queries = splitQuery(query);
17
+ var regexps = buildRegexps(queries);
18
+ var highlighters = buildHilighters(queries);
19
+ var state = { from: 0, pass: 0, limit: MAX_RESULTS, n: suid++};
20
+ var _this = this;
21
+
22
+ this.currentSuid = state.n;
23
+
24
+ if (!query) return;
25
+
26
+ var run = function() {
27
+ // stop current search thread if new search started
28
+ if (state.n != _this.currentSuid) return;
29
+
30
+ var results =
31
+ performSearch(_this.data, regexps, queries, highlighters, state);
32
+ var hasMore = (state.limit > 0 && state.pass < 4);
33
+
34
+ triggerResults.call(_this, results, !hasMore);
35
+ if (hasMore) {
36
+ setTimeout(run, 2);
37
+ }
38
+ runs++;
39
+ };
40
+ runs = 0;
41
+
42
+ // start search thread
43
+ run();
44
+ }
45
+
46
+ /* ----- Events ------ */
47
+ this.ready = function(fn) {
48
+ fn.huid = huid;
49
+ this.handlers.push(fn);
50
+ }
51
+
52
+ /* ----- Utilities ------ */
53
+ function splitQuery(query) {
54
+ return query.split(/(\s+|::?|\(\)?)/).filter(function(string) {
55
+ return string.match(/\S/);
56
+ });
57
+ }
58
+
59
+ function buildRegexps(queries) {
60
+ return queries.map(function(query) {
61
+ return new RegExp(query.replace(/(.)/g, '([$1])([^$1]*?)'), 'i');
62
+ });
63
+ }
64
+
65
+ function buildHilighters(queries) {
66
+ return queries.map(function(query) {
67
+ return query.split('').map(function(l, i) {
68
+ return '\u0001$' + (i*2+1) + '\u0002$' + (i*2+2);
69
+ }).join('');
70
+ });
71
+ }
72
+
73
+ // function longMatchRegexp(index, longIndex, regexps) {
74
+ // for (var i = regexps.length - 1; i >= 0; i--){
75
+ // if (!index.match(regexps[i]) && !longIndex.match(regexps[i])) return false;
76
+ // };
77
+ // return true;
78
+ // }
79
+
80
+
81
+ /* ----- Mathchers ------ */
82
+
83
+ /*
84
+ * This record matches if the index starts with queries[0] and the record
85
+ * matches all of the regexps
86
+ */
87
+ function matchPassBeginning(index, longIndex, queries, regexps) {
88
+ if (index.indexOf(queries[0]) != 0) return false;
89
+ for (var i=1, l = regexps.length; i < l; i++) {
90
+ if (!index.match(regexps[i]) && !longIndex.match(regexps[i]))
91
+ return false;
92
+ };
93
+ return true;
94
+ }
95
+
96
+ /*
97
+ * This record matches if the longIndex starts with queries[0] and the
98
+ * longIndex matches all of the regexps
99
+ */
100
+ function matchPassLongIndex(index, longIndex, queries, regexps) {
101
+ if (longIndex.indexOf(queries[0]) != 0) return false;
102
+ for (var i=1, l = regexps.length; i < l; i++) {
103
+ if (!longIndex.match(regexps[i]))
104
+ return false;
105
+ };
106
+ return true;
107
+ }
108
+
109
+ /*
110
+ * This record matches if the index contains queries[0] and the record
111
+ * matches all of the regexps
112
+ */
113
+ function matchPassContains(index, longIndex, queries, regexps) {
114
+ if (index.indexOf(queries[0]) == -1) return false;
115
+ for (var i=1, l = regexps.length; i < l; i++) {
116
+ if (!index.match(regexps[i]) && !longIndex.match(regexps[i]))
117
+ return false;
118
+ };
119
+ return true;
120
+ }
121
+
122
+ /*
123
+ * This record matches if regexps[0] matches the index and the record
124
+ * matches all of the regexps
125
+ */
126
+ function matchPassRegexp(index, longIndex, queries, regexps) {
127
+ if (!index.match(regexps[0])) return false;
128
+ for (var i=1, l = regexps.length; i < l; i++) {
129
+ if (!index.match(regexps[i]) && !longIndex.match(regexps[i]))
130
+ return false;
131
+ };
132
+ return true;
133
+ }
134
+
135
+
136
+ /* ----- Highlighters ------ */
137
+ function highlightRegexp(info, queries, regexps, highlighters) {
138
+ var result = createResult(info);
139
+ for (var i=0, l = regexps.length; i < l; i++) {
140
+ result.title = result.title.replace(regexps[i], highlighters[i]);
141
+ result.namespace = result.namespace.replace(regexps[i], highlighters[i]);
142
+ };
143
+ return result;
144
+ }
145
+
146
+ function hltSubstring(string, pos, length) {
147
+ return string.substring(0, pos) + '\u0001' + string.substring(pos, pos + length) + '\u0002' + string.substring(pos + length);
148
+ }
149
+
150
+ function highlightQuery(info, queries, regexps, highlighters) {
151
+ var result = createResult(info);
152
+ var pos = 0;
153
+ var lcTitle = result.title.toLowerCase();
154
+
155
+ pos = lcTitle.indexOf(queries[0]);
156
+ if (pos != -1) {
157
+ result.title = hltSubstring(result.title, pos, queries[0].length);
158
+ }
159
+
160
+ result.namespace = result.namespace.replace(regexps[0], highlighters[0]);
161
+ for (var i=1, l = regexps.length; i < l; i++) {
162
+ result.title = result.title.replace(regexps[i], highlighters[i]);
163
+ result.namespace = result.namespace.replace(regexps[i], highlighters[i]);
164
+ };
165
+ return result;
166
+ }
167
+
168
+ function createResult(info) {
169
+ var result = {};
170
+ result.title = info[0];
171
+ result.namespace = info[1];
172
+ result.path = info[2];
173
+ result.params = info[3];
174
+ result.snippet = info[4];
175
+ result.badge = info[6];
176
+ return result;
177
+ }
178
+
179
+ /* ----- Searching ------ */
180
+ function performSearch(data, regexps, queries, highlighters, state) {
181
+ var searchIndex = data.searchIndex;
182
+ var longSearchIndex = data.longSearchIndex;
183
+ var info = data.info;
184
+ var result = [];
185
+ var i = state.from;
186
+ var l = searchIndex.length;
187
+ var togo = CHUNK_SIZE;
188
+ var matchFunc, hltFunc;
189
+
190
+ while (state.pass < 4 && state.limit > 0 && togo > 0) {
191
+ if (state.pass == 0) {
192
+ matchFunc = matchPassBeginning;
193
+ hltFunc = highlightQuery;
194
+ } else if (state.pass == 1) {
195
+ matchFunc = matchPassLongIndex;
196
+ hltFunc = highlightQuery;
197
+ } else if (state.pass == 2) {
198
+ matchFunc = matchPassContains;
199
+ hltFunc = highlightQuery;
200
+ } else if (state.pass == 3) {
201
+ matchFunc = matchPassRegexp;
202
+ hltFunc = highlightRegexp;
203
+ }
204
+
205
+ for (; togo > 0 && i < l && state.limit > 0; i++, togo--) {
206
+ if (info[i].n == state.n) continue;
207
+ if (matchFunc(searchIndex[i], longSearchIndex[i], queries, regexps)) {
208
+ info[i].n = state.n;
209
+ result.push(hltFunc(info[i], queries, regexps, highlighters));
210
+ state.limit--;
211
+ }
212
+ };
213
+ if (searchIndex.length <= i) {
214
+ state.pass++;
215
+ i = state.from = 0;
216
+ } else {
217
+ state.from = i;
218
+ }
219
+ }
220
+ return result;
221
+ }
222
+
223
+ function triggerResults(results, isLast) {
224
+ this.handlers.forEach(function(fn) {
225
+ fn.call(this, results, isLast)
226
+ });
227
+ }
228
+ }
229
+
Binary file
@@ -0,0 +1,269 @@
1
+ <!DOCTYPE html>
2
+
3
+ <html>
4
+ <head>
5
+ <meta charset="UTF-8">
6
+
7
+ <title>Table of Contents - RDoc Documentation</title>
8
+
9
+ <script type="text/javascript">
10
+ var rdoc_rel_prefix = "./";
11
+ var index_rel_prefix = "./";
12
+ </script>
13
+
14
+ <script src="./js/navigation.js" defer></script>
15
+ <script src="./js/search.js" defer></script>
16
+ <script src="./js/search_index.js" defer></script>
17
+ <script src="./js/searcher.js" defer></script>
18
+ <script src="./js/darkfish.js" defer></script>
19
+
20
+ <link href="./css/fonts.css" rel="stylesheet">
21
+ <link href="./css/rdoc.css" rel="stylesheet">
22
+
23
+
24
+ <body id="top" class="table-of-contents">
25
+ <main role="main">
26
+ <h1 class="class">Table of Contents - RDoc Documentation</h1>
27
+
28
+ <h2 id="pages">Pages</h2>
29
+ <ul>
30
+ <li class="file">
31
+ <a href="CHANGELOG_md.html">CHANGELOG</a>
32
+
33
+ <ul>
34
+ <li><a href="CHANGELOG_md.html#label-Changelog">Changelog</a>
35
+ <li><a href="CHANGELOG_md.html#label-5BUnreleased-5D">[Unreleased]</a>
36
+ <li><a href="CHANGELOG_md.html#label-5B0.1.0-5D+-E2-80-93+2023-01-09">[0.1.0] – 2023-01-09</a>
37
+ </ul>
38
+ </li>
39
+ <li class="file">
40
+ <a href="LICENSE-APACHE.html">LICENSE-APACHE</a>
41
+ </li>
42
+ <li class="file">
43
+ <a href="LICENSE-MIT.html">LICENSE-MIT</a>
44
+ </li>
45
+ <li class="file">
46
+ <a href="README_md.html">README</a>
47
+
48
+ <ul>
49
+ <li><a href="README_md.html#label-truelayer-signing">truelayer-signing</a>
50
+ <li><a href="README_md.html#label-Installation">Installation</a>
51
+ <li><a href="README_md.html#label-Configuration">Configuration</a>
52
+ <li><a href="README_md.html#label-Generating+a+signature">Generating a signature</a>
53
+ <li><a href="README_md.html#label-Verifying+webhooks">Verifying webhooks</a>
54
+ <li><a href="README_md.html#label-Testing">Testing</a>
55
+ </ul>
56
+ </li>
57
+ <li class="file">
58
+ <a href="Rakefile.html">Rakefile</a>
59
+ </li>
60
+ <li class="file">
61
+ <a href="examples/sign-request/Gemfile.html">Gemfile</a>
62
+ </li>
63
+ <li class="file">
64
+ <a href="examples/sign-request/Gemfile_lock.html">Gemfile.lock</a>
65
+ </li>
66
+ <li class="file">
67
+ <a href="examples/sign-request/README_md.html">README</a>
68
+
69
+ <ul>
70
+ <li><a href="examples/sign-request/README_md.html#label-Ruby+request+signature+example">Ruby request signature example</a>
71
+ <li><a href="examples/sign-request/README_md.html#label-Run">Run</a>
72
+ </ul>
73
+ </li>
74
+ <li class="file">
75
+ <a href="examples/webhook-server/Gemfile.html">Gemfile</a>
76
+ </li>
77
+ <li class="file">
78
+ <a href="examples/webhook-server/Gemfile_lock.html">Gemfile.lock</a>
79
+ </li>
80
+ <li class="file">
81
+ <a href="examples/webhook-server/README_md.html">README</a>
82
+
83
+ <ul>
84
+ <li><a href="examples/webhook-server/README_md.html#label-Ruby+webhook+server+example">Ruby webhook server example</a>
85
+ <li><a href="examples/webhook-server/README_md.html#label-Run">Run</a>
86
+ </ul>
87
+ </li>
88
+ </ul>
89
+
90
+ <h2 id="classes">Classes and Modules</h2>
91
+ <ul>
92
+ <li class="module">
93
+ <a href="JWT.html">JWT</a>
94
+ </li>
95
+ <li class="class">
96
+ <a href="JWT/Decode.html">JWT::Decode</a>
97
+ </li>
98
+ <li class="class">
99
+ <a href="JWT/Encode.html">JWT::Encode</a>
100
+ </li>
101
+ <li class="module">
102
+ <a href="JWT/JWK.html">JWT::JWK</a>
103
+ </li>
104
+ <li class="class">
105
+ <a href="JWT/JWK/EC.html">JWT::JWK::EC</a>
106
+ </li>
107
+ <li class="module">
108
+ <a href="TrueLayerSigning.html">TrueLayerSigning</a>
109
+ </li>
110
+ <li class="class">
111
+ <a href="TrueLayerSigning/Config.html">TrueLayerSigning::Config</a>
112
+ </li>
113
+ <li class="class">
114
+ <a href="TrueLayerSigning/Error.html">TrueLayerSigning::Error</a>
115
+ </li>
116
+ <li class="class">
117
+ <a href="TrueLayerSigning/JwsBase.html">TrueLayerSigning::JwsBase</a>
118
+ </li>
119
+ <li class="class">
120
+ <a href="TrueLayerSigning/JwsHeader.html">TrueLayerSigning::JwsHeader</a>
121
+ </li>
122
+ <li class="class">
123
+ <a href="TrueLayerSigning/Signer.html">TrueLayerSigning::Signer</a>
124
+ </li>
125
+ <li class="class">
126
+ <a href="TrueLayerSigning/Verifier.html">TrueLayerSigning::Verifier</a>
127
+ </li>
128
+ <li class="class">
129
+ <a href="TrueLayerSigningExamples.html">TrueLayerSigningExamples</a>
130
+ </li>
131
+ </ul>
132
+
133
+ <h2 id="methods">Methods</h2>
134
+ <ul>
135
+
136
+ <li class="method">
137
+ <a href="TrueLayerSigning.html#method-c-extract_jws_header">::extract_jws_header</a>
138
+ &mdash;
139
+ <span class="container">TrueLayerSigning</span>
140
+
141
+ <li class="method">
142
+ <a href="TrueLayerSigning/Verifier.html#method-c-new">::new</a>
143
+ &mdash;
144
+ <span class="container">TrueLayerSigning::Verifier</span>
145
+
146
+ <li class="method">
147
+ <a href="TrueLayerSigning/Config.html#method-c-new">::new</a>
148
+ &mdash;
149
+ <span class="container">TrueLayerSigning::Config</span>
150
+
151
+ <li class="method">
152
+ <a href="TrueLayerSigning/JwsHeader.html#method-c-new">::new</a>
153
+ &mdash;
154
+ <span class="container">TrueLayerSigning::JwsHeader</span>
155
+
156
+ <li class="method">
157
+ <a href="TrueLayerSigning/JwsBase.html#method-c-new">::new</a>
158
+ &mdash;
159
+ <span class="container">TrueLayerSigning::JwsBase</span>
160
+
161
+ <li class="method">
162
+ <a href="TrueLayerSigning/Verifier.html#method-c-parse_tl_signature">::parse_tl_signature</a>
163
+ &mdash;
164
+ <span class="container">TrueLayerSigning::Verifier</span>
165
+
166
+ <li class="method">
167
+ <a href="TrueLayerSigningExamples.html#method-c-run_webhook_server">::run_webhook_server</a>
168
+ &mdash;
169
+ <span class="container">TrueLayerSigningExamples</span>
170
+
171
+ <li class="method">
172
+ <a href="TrueLayerSigning/Config.html#method-c-setup">::setup</a>
173
+ &mdash;
174
+ <span class="container">TrueLayerSigning::Config</span>
175
+
176
+ <li class="method">
177
+ <a href="TrueLayerSigning.html#method-c-sign_with_pem">::sign_with_pem</a>
178
+ &mdash;
179
+ <span class="container">TrueLayerSigning</span>
180
+
181
+ <li class="method">
182
+ <a href="TrueLayerSigningExamples.html#method-c-test_signature_endpoint">::test_signature_endpoint</a>
183
+ &mdash;
184
+ <span class="container">TrueLayerSigningExamples</span>
185
+
186
+ <li class="method">
187
+ <a href="TrueLayerSigning.html#method-c-verify_with_jwks">::verify_with_jwks</a>
188
+ &mdash;
189
+ <span class="container">TrueLayerSigning</span>
190
+
191
+ <li class="method">
192
+ <a href="TrueLayerSigning.html#method-c-verify_with_pem">::verify_with_pem</a>
193
+ &mdash;
194
+ <span class="container">TrueLayerSigning</span>
195
+
196
+ <li class="method">
197
+ <a href="TrueLayerSigning/JwsBase.html#method-i-add_header">#add_header</a>
198
+ &mdash;
199
+ <span class="container">TrueLayerSigning::JwsBase</span>
200
+
201
+ <li class="method">
202
+ <a href="JWT/JWK/EC.html#method-i-create_ec_key">#create_ec_key</a>
203
+ &mdash;
204
+ <span class="container">JWT::JWK::EC</span>
205
+
206
+ <li class="method">
207
+ <a href="TrueLayerSigning/JwsHeader.html#method-i-filter_headers">#filter_headers</a>
208
+ &mdash;
209
+ <span class="container">TrueLayerSigning::JwsHeader</span>
210
+
211
+ <li class="method">
212
+ <a href="TrueLayerSigning/Verifier.html#method-i-require_header">#require_header</a>
213
+ &mdash;
214
+ <span class="container">TrueLayerSigning::Verifier</span>
215
+
216
+ <li class="method">
217
+ <a href="TrueLayerSigning/Verifier.html#method-i-require_headers">#require_headers</a>
218
+ &mdash;
219
+ <span class="container">TrueLayerSigning::Verifier</span>
220
+
221
+ <li class="method">
222
+ <a href="TrueLayerSigning/JwsBase.html#method-i-set_body">#set_body</a>
223
+ &mdash;
224
+ <span class="container">TrueLayerSigning::JwsBase</span>
225
+
226
+ <li class="method">
227
+ <a href="TrueLayerSigning/JwsBase.html#method-i-set_headers">#set_headers</a>
228
+ &mdash;
229
+ <span class="container">TrueLayerSigning::JwsBase</span>
230
+
231
+ <li class="method">
232
+ <a href="TrueLayerSigning/Signer.html#method-i-set_jku">#set_jku</a>
233
+ &mdash;
234
+ <span class="container">TrueLayerSigning::Signer</span>
235
+
236
+ <li class="method">
237
+ <a href="TrueLayerSigning/JwsBase.html#method-i-set_method">#set_method</a>
238
+ &mdash;
239
+ <span class="container">TrueLayerSigning::JwsBase</span>
240
+
241
+ <li class="method">
242
+ <a href="TrueLayerSigning/JwsBase.html#method-i-set_path">#set_path</a>
243
+ &mdash;
244
+ <span class="container">TrueLayerSigning::JwsBase</span>
245
+
246
+ <li class="method">
247
+ <a href="TrueLayerSigning/Signer.html#method-i-sign">#sign</a>
248
+ &mdash;
249
+ <span class="container">TrueLayerSigning::Signer</span>
250
+
251
+ <li class="method">
252
+ <a href="TrueLayerSigning/JwsHeader.html#method-i-to_h">#to_h</a>
253
+ &mdash;
254
+ <span class="container">TrueLayerSigning::JwsHeader</span>
255
+
256
+ <li class="method">
257
+ <a href="TrueLayerSigning/Verifier.html#method-i-verify">#verify</a>
258
+ &mdash;
259
+ <span class="container">TrueLayerSigning::Verifier</span>
260
+ </ul>
261
+ </main>
262
+
263
+
264
+ <footer id="validator-badges" role="contentinfo">
265
+ <p><a href="https://validator.w3.org/check/referer">Validate</a>
266
+ <p>Generated by <a href="https://ruby.github.io/rdoc/">RDoc</a> 6.5.0.
267
+ <p>Based on <a href="http://deveiate.org/projects/Darkfish-RDoc/">Darkfish</a> by <a href="http://deveiate.org">Michael Granger</a>.
268
+ </footer>
269
+
@@ -0,0 +1,4 @@
1
+ source "https://rubygems.org"
2
+
3
+ gem "http"
4
+ gem "truelayer-signing"
@@ -0,0 +1,41 @@
1
+ GEM
2
+ remote: https://rubygems.org/
3
+ specs:
4
+ addressable (2.8.1)
5
+ public_suffix (>= 2.0.2, < 6.0)
6
+ domain_name (0.5.20190701)
7
+ unf (>= 0.0.5, < 1.0.0)
8
+ ffi (1.15.5)
9
+ ffi-compiler (1.0.1)
10
+ ffi (>= 1.0.0)
11
+ rake
12
+ http (5.1.1)
13
+ addressable (~> 2.8)
14
+ http-cookie (~> 1.0)
15
+ http-form_data (~> 2.2)
16
+ llhttp-ffi (~> 0.4.0)
17
+ http-cookie (1.0.5)
18
+ domain_name (~> 0.5)
19
+ http-form_data (2.3.0)
20
+ jwt (2.6.0)
21
+ llhttp-ffi (0.4.0)
22
+ ffi-compiler (~> 1.0)
23
+ rake (~> 13.0)
24
+ public_suffix (5.0.1)
25
+ rake (13.0.6)
26
+ truelayer-signing (0.1.0)
27
+ jwt (= 2.6)
28
+ unf (0.1.4)
29
+ unf_ext
30
+ unf_ext (0.0.8.2)
31
+
32
+ PLATFORMS
33
+ arm64-darwin-21
34
+ ruby
35
+
36
+ DEPENDENCIES
37
+ http
38
+ truelayer-signing
39
+
40
+ BUNDLED WITH
41
+ 2.4.1
@@ -0,0 +1,27 @@
1
+ # Ruby request signature example
2
+
3
+ Sends a signed request to `https://api.truelayer-sandbox.com/test-signature`.
4
+
5
+ ## Run
6
+
7
+ Set the following environment variables:
8
+
9
+ * `TRUELAYER_SIGNING_ACCESS_TOKEN` – a valid JWT access token for the `payments` scope (see our
10
+ [docs](https://docs.truelayer.com/docs/retrieve-a-token-in-your-server)).
11
+ * `TRUELAYER_SIGNING_CERTIFICATE_ID` – the certificate/key UUID associated with your public key
12
+ uploaded at [console.truelayer.com](https://console.truelayer.com).
13
+ * `TRUELAYER_SIGNING_PRIVATE_KEY` – the private key PEM string that matches the certificate ID of the
14
+ uploaded public key. Should have the same format as [this example private
15
+ key](https://github.com/TrueLayer/truelayer-signing/blob/main/test-resources/ec512-private.pem).
16
+
17
+ Install the required dependencies:
18
+
19
+ ```sh
20
+ $ bundle
21
+ ```
22
+
23
+ Execute the request-signing example script:
24
+
25
+ ```sh
26
+ $ ruby main.rb
27
+ ```
@@ -0,0 +1,46 @@
1
+ require "http"
2
+ require "securerandom"
3
+ require "truelayer-signing"
4
+
5
+ class TrueLayerSigningExamples
6
+ # Set required environment variables
7
+ TRUELAYER_SIGNING_ACCESS_TOKEN = ENV.fetch("TRUELAYER_SIGNING_ACCESS_TOKEN", nil).freeze
8
+ TRUELAYER_SIGNING_BASE_URL = "https://api.truelayer-sandbox.com".freeze
9
+
10
+ raise(StandardError, "TRUELAYER_SIGNING_ACCESS_TOKEN is missing") \
11
+ if TRUELAYER_SIGNING_ACCESS_TOKEN.nil? || TRUELAYER_SIGNING_ACCESS_TOKEN.empty?
12
+
13
+ class << self
14
+ def test_signature_endpoint
15
+ url = "#{TRUELAYER_SIGNING_BASE_URL}/test-signature"
16
+ idempotency_key = SecureRandom.uuid
17
+
18
+ # A random body string is enough for this request as the `/test-signature` endpoint does not
19
+ # require any schema, it simply checks the signature is valid against what's received.
20
+ body = "body-#{SecureRandom.uuid}"
21
+
22
+ # Generate a `Tl-Signature`
23
+ signature = TrueLayerSigning.sign_with_pem
24
+ .set_method("POST")
25
+ .set_path("/test-signature")
26
+ # Optional: `/test-signature` does not require any headers, but we may sign some anyway.
27
+ # All signed headers *must* be included unmodified in the request.
28
+ .add_header("Idempotency-Key", idempotency_key)
29
+ .add_header("X-Bar-Header", "abc123")
30
+ .set_body(body)
31
+ .sign
32
+
33
+ response = HTTP.auth("Bearer #{TRUELAYER_SIGNING_ACCESS_TOKEN}")
34
+ .headers(idempotency_key: idempotency_key)
35
+ .headers(x_bar_header: "abc123")
36
+ .headers(tl_signature: signature)
37
+ .post(url, body: body)
38
+
39
+ return puts "✓ Signature is valid" if response.status.success?
40
+
41
+ puts JSON.pretty_generate(JSON.parse(response.to_s))
42
+ end
43
+ end
44
+ end
45
+
46
+ TrueLayerSigningExamples.test_signature_endpoint
@@ -0,0 +1,3 @@
1
+ source "https://rubygems.org"
2
+
3
+ gem "truelayer-signing"
@@ -0,0 +1,15 @@
1
+ GEM
2
+ remote: https://rubygems.org/
3
+ specs:
4
+ jwt (2.6.0)
5
+ truelayer-signing (0.1.0)
6
+ jwt (= 2.6)
7
+
8
+ PLATFORMS
9
+ arm64-darwin-21
10
+
11
+ DEPENDENCIES
12
+ truelayer-signing
13
+
14
+ BUNDLED WITH
15
+ 2.4.1
@@ -0,0 +1,30 @@
1
+ # Ruby webhook server example
2
+
3
+ An HTTP server that can receive and verify signed TrueLayer webhooks.
4
+
5
+ ## Run
6
+
7
+ Install the required dependencies:
8
+
9
+ ```sh
10
+ $ bundle
11
+ ```
12
+
13
+ Run the server locally:
14
+
15
+ ```sh
16
+ $ ruby main.rb
17
+ ```
18
+
19
+ Send a valid webhook that was signed for the path `/hook/d7a2c49d-110a-4ed2-a07d-8fdb3ea6424b`:
20
+
21
+ ```sh
22
+ curl -iX POST -H "Content-Type: application/json" \
23
+ -H "X-Tl-Webhook-Timestamp: 2022-03-11T14:00:33Z" \
24
+ -H "Tl-Signature: eyJhbGciOiJFUzUxMiIsImtpZCI6IjFmYzBlNTlmLWIzMzUtNDdjYS05OWE5LTczNzQ5NTc1NmE1OCIsInRsX3ZlcnNpb24iOiIyIiwidGxfaGVhZGVycyI6IngtdGwtd2ViaG9vay10aW1lc3RhbXAiLCJqa3UiOiJodHRwczovL3dlYmhvb2tzLnRydWVsYXllci5jb20vLndlbGwta25vd24vandrcyJ9..AE_QsBRhnsMkcRzd42wvY1e2HruUhkOgjuZKktGH_WmbD7rBzoaEHUuF36IxyyvCbLajd3MBExNmzjbrOQsGaspwAI5DcGVMFLKUhB7ZzUlTP9up3eNUrdwWyyfBWDQb-qmEuLnrhFDJvgCXEqlV5OLrt-O7LaRAJ4f9KHsZLQ_j2vPC" \
25
+ -d "{\"event_type\":\"payout_settled\",\"event_schema_version\":1,\"event_id\":\"8fb9fb4e-bb2b-400b-af64-59e5dde74bad\",\"event_body\":{\"transaction_id\":\"c34c8721-66a9-49f6-a229-284efcf88a02\",\"settled_at\":\"2022-03-11T14:00:32.933000Z\"}}" \
26
+ http://localhost:4567/hook/d7a2c49d-110a-4ed2-a07d-8fdb3ea6424b
27
+ ```
28
+
29
+ Modifying the `X-Tl-Webhook-Timestamp` header, the body or the path of the request will cause the
30
+ above signature to be invalid.