@depup/hapi 18.1.0-depup.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.
@@ -0,0 +1,198 @@
1
+ 'use strict';
2
+
3
+ const Boom = require('boom');
4
+ const Hoek = require('hoek');
5
+ const Joi = require('joi');
6
+
7
+
8
+ const internals = {};
9
+
10
+
11
+ exports.compile = function (rule) {
12
+
13
+ // null, undefined, true - anything allowed
14
+ // false - nothing allowed
15
+ // {...} - ... allowed
16
+
17
+ return (rule === false) ?
18
+ Joi.object({}).allow(null) :
19
+ (typeof rule === 'function' ?
20
+ rule :
21
+ !rule || rule === true ? null : Joi.compile(rule)); // false tested earlier
22
+
23
+ };
24
+
25
+
26
+ exports.headers = function (request) {
27
+
28
+ return internals.input('headers', request);
29
+ };
30
+
31
+
32
+ exports.params = function (request) {
33
+
34
+ return internals.input('params', request);
35
+ };
36
+
37
+
38
+ exports.payload = function (request) {
39
+
40
+ if (request.method === 'get' ||
41
+ request.method === 'head') { // When route.method is '*'
42
+
43
+ return;
44
+ }
45
+
46
+ return internals.input('payload', request);
47
+ };
48
+
49
+
50
+ exports.query = function (request) {
51
+
52
+ return internals.input('query', request);
53
+ };
54
+
55
+
56
+ exports.state = function (request) {
57
+
58
+ return internals.input('state', request);
59
+ };
60
+
61
+
62
+ internals.input = async function (source, request) {
63
+
64
+ const localOptions = {
65
+ context: {
66
+ headers: request.headers,
67
+ params: request.params,
68
+ query: request.query,
69
+ payload: request.payload,
70
+ state: request.state,
71
+ auth: request.auth,
72
+ app: {
73
+ route: request.route.settings.app,
74
+ request: request.app
75
+ }
76
+ }
77
+ };
78
+
79
+ delete localOptions.context[source];
80
+ Hoek.merge(localOptions, request.route.settings.validate.options);
81
+
82
+ try {
83
+ const schema = request.route.settings.validate[source];
84
+ const bind = request.route.settings.bind;
85
+
86
+ var value = await (typeof schema !== 'function' ? Joi.validate(request[source], schema, localOptions) : schema.call(bind, request[source], localOptions));
87
+ return;
88
+ }
89
+ catch (err) {
90
+ var validationError = err;
91
+ }
92
+ finally {
93
+ request.orig[source] = request[source];
94
+ if (value !== undefined) {
95
+ request[source] = value;
96
+ }
97
+ }
98
+
99
+ if (request.route.settings.validate.failAction === 'ignore') {
100
+ return;
101
+ }
102
+
103
+ // Prepare error
104
+
105
+ const defaultError = validationError.isBoom ? validationError : Boom.badRequest(`Invalid request ${source} input`);
106
+ const detailedError = Boom.boomify(validationError, { statusCode: 400, override: false });
107
+ detailedError.output.payload.validation = { source, keys: [] };
108
+ if (validationError.details) {
109
+ for (const details of validationError.details) {
110
+ const path = details.path;
111
+ detailedError.output.payload.validation.keys.push(Hoek.escapeHtml(path.join('.')));
112
+ }
113
+ }
114
+
115
+ if (request.route.settings.validate.errorFields) {
116
+ for (const field in request.route.settings.validate.errorFields) {
117
+ detailedError.output.payload[field] = request.route.settings.validate.errorFields[field];
118
+ }
119
+ }
120
+
121
+ return request._core.toolkit.failAction(request, request.route.settings.validate.failAction, defaultError, { details: detailedError, tags: ['validation', 'error', source] });
122
+ };
123
+
124
+
125
+ exports.response = async function (request) {
126
+
127
+ if (request.route.settings.response.sample) {
128
+ const currentSample = Math.ceil((Math.random() * 100));
129
+ if (currentSample > request.route.settings.response.sample) {
130
+ return;
131
+ }
132
+ }
133
+
134
+ const response = request.response;
135
+ const statusCode = response.isBoom ? response.output.statusCode : response.statusCode;
136
+
137
+ const statusSchema = request.route.settings.response.status[statusCode];
138
+ if (statusCode >= 400 &&
139
+ !statusSchema) {
140
+
141
+ return; // Do not validate errors by default
142
+ }
143
+
144
+ const schema = statusSchema !== undefined ? statusSchema : request.route.settings.response.schema;
145
+ if (schema === null) {
146
+ return; // No rules
147
+ }
148
+
149
+ if (!response.isBoom &&
150
+ request.response.variety !== 'plain') {
151
+
152
+ throw Boom.badImplementation('Cannot validate non-object response');
153
+ }
154
+
155
+ const localOptions = {
156
+ context: {
157
+ headers: request.headers,
158
+ params: request.params,
159
+ query: request.query,
160
+ payload: request.payload,
161
+ state: request.state,
162
+ auth: request.auth,
163
+ app: {
164
+ route: request.route.settings.app,
165
+ request: request.app
166
+ }
167
+ }
168
+ };
169
+
170
+ const source = response.isBoom ? response.output.payload : response.source;
171
+ Hoek.merge(localOptions, request.route.settings.response.options);
172
+
173
+ try {
174
+ let value;
175
+
176
+ if (typeof schema !== 'function') {
177
+ value = await Joi.validate(source, schema, localOptions);
178
+ }
179
+ else {
180
+ value = await schema(source, localOptions);
181
+ }
182
+
183
+ if (value !== undefined &&
184
+ request.route.settings.response.modify) {
185
+
186
+ if (response.isBoom) {
187
+ response.output.payload = value;
188
+ }
189
+ else {
190
+ response.source = value;
191
+ }
192
+ }
193
+ }
194
+ catch (err) {
195
+
196
+ return request._core.toolkit.failAction(request, request.route.settings.response.failAction, err, { tags: ['validation', 'response', 'error'] });
197
+ }
198
+ };