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.
- checksums.yaml +7 -0
- data/CHANGELOG.md +14 -0
- data/LICENSE-APACHE +176 -0
- data/LICENSE-MIT +21 -0
- data/README.md +82 -0
- data/Rakefile +8 -0
- data/doc/CHANGELOG_md.html +132 -0
- data/doc/JWT/Decode.html +97 -0
- data/doc/JWT/Encode.html +97 -0
- data/doc/JWT/JWK/EC.html +169 -0
- data/doc/JWT/JWK.html +91 -0
- data/doc/JWT.html +95 -0
- data/doc/LICENSE-APACHE.html +177 -0
- data/doc/LICENSE-MIT.html +105 -0
- data/doc/README_md.html +197 -0
- data/doc/Rakefile.html +106 -0
- data/doc/TrueLayerSigning/Config.html +211 -0
- data/doc/TrueLayerSigning/Error.html +97 -0
- data/doc/TrueLayerSigning/JwsBase.html +317 -0
- data/doc/TrueLayerSigning/JwsHeader.html +268 -0
- data/doc/TrueLayerSigning/Signer.html +186 -0
- data/doc/TrueLayerSigning/Verifier.html +327 -0
- data/doc/TrueLayerSigning.html +226 -0
- data/doc/TrueLayerSigningExamples.html +217 -0
- data/doc/created.rid +21 -0
- data/doc/css/fonts.css +167 -0
- data/doc/css/rdoc.css +662 -0
- data/doc/examples/sign-request/Gemfile.html +99 -0
- data/doc/examples/sign-request/Gemfile_lock.html +143 -0
- data/doc/examples/sign-request/README_md.html +138 -0
- data/doc/examples/webhook-server/Gemfile.html +99 -0
- data/doc/examples/webhook-server/Gemfile_lock.html +142 -0
- data/doc/examples/webhook-server/README_md.html +139 -0
- data/doc/fonts/Lato-Light.ttf +0 -0
- data/doc/fonts/Lato-LightItalic.ttf +0 -0
- data/doc/fonts/Lato-Regular.ttf +0 -0
- data/doc/fonts/Lato-RegularItalic.ttf +0 -0
- data/doc/fonts/SourceCodePro-Bold.ttf +0 -0
- data/doc/fonts/SourceCodePro-Regular.ttf +0 -0
- data/doc/images/add.png +0 -0
- data/doc/images/arrow_up.png +0 -0
- data/doc/images/brick.png +0 -0
- data/doc/images/brick_link.png +0 -0
- data/doc/images/bug.png +0 -0
- data/doc/images/bullet_black.png +0 -0
- data/doc/images/bullet_toggle_minus.png +0 -0
- data/doc/images/bullet_toggle_plus.png +0 -0
- data/doc/images/date.png +0 -0
- data/doc/images/delete.png +0 -0
- data/doc/images/find.png +0 -0
- data/doc/images/loadingAnimation.gif +0 -0
- data/doc/images/macFFBgHack.png +0 -0
- data/doc/images/package.png +0 -0
- data/doc/images/page_green.png +0 -0
- data/doc/images/page_white_text.png +0 -0
- data/doc/images/page_white_width.png +0 -0
- data/doc/images/plugin.png +0 -0
- data/doc/images/ruby.png +0 -0
- data/doc/images/tag_blue.png +0 -0
- data/doc/images/tag_green.png +0 -0
- data/doc/images/transparent.png +0 -0
- data/doc/images/wrench.png +0 -0
- data/doc/images/wrench_orange.png +0 -0
- data/doc/images/zoom.png +0 -0
- data/doc/index.html +118 -0
- data/doc/js/darkfish.js +84 -0
- data/doc/js/navigation.js +105 -0
- data/doc/js/navigation.js.gz +0 -0
- data/doc/js/search.js +110 -0
- data/doc/js/search_index.js +1 -0
- data/doc/js/search_index.js.gz +0 -0
- data/doc/js/searcher.js +229 -0
- data/doc/js/searcher.js.gz +0 -0
- data/doc/table_of_contents.html +269 -0
- data/examples/sign-request/Gemfile +4 -0
- data/examples/sign-request/Gemfile.lock +41 -0
- data/examples/sign-request/README.md +27 -0
- data/examples/sign-request/main.rb +46 -0
- data/examples/webhook-server/Gemfile +3 -0
- data/examples/webhook-server/Gemfile.lock +15 -0
- data/examples/webhook-server/README.md +30 -0
- data/examples/webhook-server/main.rb +98 -0
- data/lib/truelayer-signing/config.rb +21 -0
- data/lib/truelayer-signing/errors.rb +3 -0
- data/lib/truelayer-signing/jwt.rb +20 -0
- data/lib/truelayer-signing/signer.rb +34 -0
- data/lib/truelayer-signing/utils.rb +90 -0
- data/lib/truelayer-signing/verifier.rb +76 -0
- data/lib/truelayer-signing.rb +35 -0
- data/test/test-truelayer-signing.rb +372 -0
- data/truelayer-signing.gemspec +25 -0
- metadata +151 -0
Binary file
|
data/doc/js/searcher.js
ADDED
@@ -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
|
+
—
|
139
|
+
<span class="container">TrueLayerSigning</span>
|
140
|
+
|
141
|
+
<li class="method">
|
142
|
+
<a href="TrueLayerSigning/Verifier.html#method-c-new">::new</a>
|
143
|
+
—
|
144
|
+
<span class="container">TrueLayerSigning::Verifier</span>
|
145
|
+
|
146
|
+
<li class="method">
|
147
|
+
<a href="TrueLayerSigning/Config.html#method-c-new">::new</a>
|
148
|
+
—
|
149
|
+
<span class="container">TrueLayerSigning::Config</span>
|
150
|
+
|
151
|
+
<li class="method">
|
152
|
+
<a href="TrueLayerSigning/JwsHeader.html#method-c-new">::new</a>
|
153
|
+
—
|
154
|
+
<span class="container">TrueLayerSigning::JwsHeader</span>
|
155
|
+
|
156
|
+
<li class="method">
|
157
|
+
<a href="TrueLayerSigning/JwsBase.html#method-c-new">::new</a>
|
158
|
+
—
|
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
|
+
—
|
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
|
+
—
|
169
|
+
<span class="container">TrueLayerSigningExamples</span>
|
170
|
+
|
171
|
+
<li class="method">
|
172
|
+
<a href="TrueLayerSigning/Config.html#method-c-setup">::setup</a>
|
173
|
+
—
|
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
|
+
—
|
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
|
+
—
|
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
|
+
—
|
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
|
+
—
|
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
|
+
—
|
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
|
+
—
|
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
|
+
—
|
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
|
+
—
|
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
|
+
—
|
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
|
+
—
|
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
|
+
—
|
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
|
+
—
|
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
|
+
—
|
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
|
+
—
|
244
|
+
<span class="container">TrueLayerSigning::JwsBase</span>
|
245
|
+
|
246
|
+
<li class="method">
|
247
|
+
<a href="TrueLayerSigning/Signer.html#method-i-sign">#sign</a>
|
248
|
+
—
|
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
|
+
—
|
254
|
+
<span class="container">TrueLayerSigning::JwsHeader</span>
|
255
|
+
|
256
|
+
<li class="method">
|
257
|
+
<a href="TrueLayerSigning/Verifier.html#method-i-verify">#verify</a>
|
258
|
+
—
|
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,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,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.
|