lib/schema.js

Maintainability

74.64

Lines of code

348

Created with Raphaël 2.1.002550751002016-7-102016-6-102016-5-112016-4-112016-3-122016-2-112016-1-12

2016-8-9
Maintainability: 74.64

Created with Raphaël 2.1.001002003004002016-7-102016-6-102016-5-112016-4-112016-3-122016-2-112016-1-12

2016-8-9
Lines of Code: 348

Difficulty

29.36

Estimated Errors

5.74

Function weight

By Complexity

Created with Raphaël 2.1.0<anonymous>3

By SLOC

Created with Raphaël 2.1.0<anonymous>6
1
'use strict';
Column: 1 "Use the function form of "use strict"."
2
 
3
// Load modules
4
 
5
const Joi = require('joi');
Column: 1 "'const' is available in ES6 (use 'esversion: 6') or Mozilla JS extensions (use moz)."
Column: 13 "'require' is not defined."
6
const Hoek = require('hoek');
Column: 1 "'const' is available in ES6 (use 'esversion: 6') or Mozilla JS extensions (use moz)."
Column: 14 "'require' is not defined."
7
 
8
 
9
// Declare internals
10
 
11
const internals = {};
Column: 1 "'const' is available in ES6 (use 'esversion: 6') or Mozilla JS extensions (use moz)."
12
 
13
 
14
exports.apply = function (type, options, message) {
Column: 1 "'exports' is not defined."
15
 
16
    const result = Joi.validate(options, internals[type]);
Column: 5 "'const' is available in ES6 (use 'esversion: 6') or Mozilla JS extensions (use moz)."
17
    Hoek.assert(!result.error, 'Invalid', type, 'options', message ? '(' + message + ')' : '', result.error && result.error.annotate());
18
    return result.value;
19
};
20
 
21
 
22
internals.access = Joi.object({
23
    entity: Joi.string().valid('user', 'app', 'any'),
24
    scope: [false, Joi.array().items(Joi.string()).single().min(1)]
25
});
26
 
27
 
28
internals.auth = Joi.alternatives([
29
    Joi.string(),
30
    internals.access.keys({
31
        mode: Joi.string().valid('required', 'optional', 'try'),
32
        strategy: Joi.string(),
33
        strategies: Joi.array().items(Joi.string()).min(1),
34
        access: Joi.array().items(internals.access.min(1)).single().min(1),
35
        payload: [
36
            Joi.string().valid('required', 'optional'),
37
            Joi.boolean()
38
        ]
39
    })
40
        .without('strategy', 'strategies')
41
        .without('access', ['scope', 'entity'])
42
]);
43
 
44
 
45
internals.event = Joi.object({
46
    method: Joi.array().items(Joi.func()).single(),
47
    options: Joi.object({
48
        before: Joi.array().items(Joi.string()).single(),
49
        after: Joi.array().items(Joi.string()).single(),
50
        bind: Joi.any(),
51
        sandbox: Joi.string().valid('connection', 'plugin')
52
    })
53
        .default({})
54
});
55
 
56
 
57
internals.exts = Joi.array().items(internals.event.keys({ type: Joi.string().required() })).single();
58
 
59
 
60
internals.routeBase = Joi.object({
61
    app: Joi.object().allow(null),
62
    auth: internals.auth.allow(false),
63
    bind: Joi.object().allow(null),
64
    cache: Joi.object({
65
        expiresIn: Joi.number(),
66
        expiresAt: Joi.string(),
67
        privacy: Joi.string().valid('default', 'public', 'private'),
68
        statuses: Joi.array().items(Joi.number().integer().min(200)).min(1).single(),
69
        otherwise: Joi.string().required()
70
    })
71
        .allow(false),
72
    cors: Joi.object({
73
        origin: Joi.array().min(1),
74
        maxAge: Joi.number(),
75
        headers: Joi.array().items(Joi.string()),
76
        additionalHeaders: Joi.array().items(Joi.string()),
77
        exposedHeaders: Joi.array().items(Joi.string()),
78
        additionalExposedHeaders: Joi.array().items(Joi.string()),
79
        credentials: Joi.boolean()
80
    })
81
        .allow(false, true),
82
    ext: Joi.object({
83
        onPreAuth: Joi.array().items(internals.event).single(),
84
        onPostAuth: Joi.array().items(internals.event).single(),
85
        onPreHandler: Joi.array().items(internals.event).single(),
86
        onPostHandler: Joi.array().items(internals.event).single(),
87
        onPreResponse: Joi.array().items(internals.event).single()
88
    })
89
        .default({}),
90
    files: Joi.object({
91
        relativeTo: Joi.string().regex(/^([\/\.])|([A-Za-z]:\\)|(\\\\)/).required()
92
    }),
93
    json: Joi.object({
94
        replacer: Joi.alternatives(Joi.func(), Joi.array()).allow(null),
95
        space: Joi.number().allow(null),
96
        suffix: Joi.string().allow(null)
97
    }),
98
    jsonp: Joi.string(),
99
    payload: Joi.object({
100
        output: Joi.string().valid('data', 'stream', 'file'),
101
        parse: Joi.boolean().allow('gunzip'),
102
        allow: [
103
            Joi.string(),
104
            Joi.array()
105
        ],
106
        override: Joi.string(),
107
        maxBytes: Joi.number(),
108
        uploads: Joi.string(),
109
        failAction: Joi.string().valid('error', 'log', 'ignore'),
110
        timeout: Joi.number().integer().positive().allow(false),
111
        defaultContentType: Joi.string()
112
    }),
113
    plugins: Joi.object(),
114
    response: Joi.object({
115
        emptyStatusCode: Joi.number().valid(200, 204),
116
        failAction: Joi.string().valid('error', 'log'),
117
        modify: Joi.boolean(),
118
        options: Joi.object(),
119
        ranges: Joi.boolean(),
120
        sample: Joi.number().min(0).max(100),
121
        schema: Joi.alternatives(Joi.object(), Joi.array(), Joi.func()).allow(true, false),
122
        status: Joi.object().pattern(/\d\d\d/, Joi.alternatives(Joi.object(), Joi.array(), Joi.func()).allow(true, false))
123
    })
124
        .without('modify', 'sample')
125
        .assert('options.stripUnknown', Joi.ref('modify'), 'meet requirement of having peer modify set to true'),
126
    security: Joi.object({
127
        hsts: [
128
            Joi.object({
129
                maxAge: Joi.number(),
130
                includeSubdomains: Joi.boolean(),
131
                includeSubDomains: Joi.boolean(),
132
                preload: Joi.boolean()
133
            }),
134
            Joi.boolean(),
135
            Joi.number()
136
        ],
137
        xframe: [
138
            Joi.boolean(),
139
            Joi.string().valid('sameorigin', 'deny'),
140
            Joi.object({
141
                rule: Joi.string().valid('sameorigin', 'deny', 'allow-from'),
142
                source: Joi.string()
143
            })
144
        ],
145
        xss: Joi.boolean(),
146
        noOpen: Joi.boolean(),
147
        noSniff: Joi.boolean()
148
    })
149
        .allow(null, false, true),
150
    state: Joi.object({
151
        parse: Joi.boolean(),
152
        failAction: Joi.string().valid('error', 'log', 'ignore')
153
    }),
154
    timeout: Joi.object({
155
        socket: Joi.number().integer().positive().allow(false),
156
        server: Joi.number().integer().positive().allow(false).required()
157
    }),
158
    validate: Joi.object({
159
        headers: Joi.alternatives(Joi.object(), Joi.array(), Joi.func()).allow(null, false, true),
160
        params: Joi.alternatives(Joi.object(), Joi.array(), Joi.func()).allow(null, false, true),
161
        query: Joi.alternatives(Joi.object(), Joi.array(), Joi.func()).allow(null, false, true),
162
        payload: Joi.alternatives(Joi.object(), Joi.array(), Joi.func()).allow(null, false, true),
163
        failAction: [
164
            Joi.string().valid('error', 'log', 'ignore'),
165
            Joi.func()
166
        ],
167
        errorFields: Joi.object(),
168
        options: Joi.object()
169
    })
170
});
171
 
172
 
173
internals.connectionBase = Joi.object({
174
    app: Joi.object().allow(null),
175
    compression: Joi.boolean(),
176
    load: Joi.object(),
177
    plugins: Joi.object(),
178
    router: Joi.object({
179
        isCaseSensitive: Joi.boolean(),
180
        stripTrailingSlash: Joi.boolean()
181
    }),
182
    routes: internals.routeBase,
183
    state: Joi.object()                                     // Cookie defaults
184
});
185
 
186
 
187
internals.server = Joi.object({
188
    app: Joi.object().allow(null),
189
    cache: Joi.allow(null),                                 // Validated elsewhere
190
    connections: internals.connectionBase,
191
    debug: Joi.object({
192
        request: Joi.array().allow(false),
193
        log: Joi.array().allow(false)
194
    }).allow(false),
195
    load: Joi.object(),
196
    mime: Joi.object(),
197
    plugins: Joi.object(),
198
    useDomains: Joi.boolean()
199
});
200
 
201
 
202
internals.connection = internals.connectionBase.keys({
203
    autoListen: Joi.boolean(),
204
    host: Joi.string().hostname(),
205
    address: Joi.string().hostname(),
206
    labels: Joi.array().items(Joi.string()).single(),
207
    listener: Joi.any(),
208
    port: Joi.alternatives([
209
        Joi.number().integer().min(0),          // TCP port
210
        Joi.string().regex(/\//),               // Unix domain socket
211
        Joi.string().regex(/^\\\\\.\\pipe\\/)   // Windows named pipe
212
    ])
213
        .allow(null),
214
    tls: Joi.alternatives([
215
        Joi.object().allow(null),
216
        Joi.boolean()
217
    ]),
218
    uri: Joi.string().regex(/[^/]$/)
219
});
220
 
221
 
222
internals.vhost = Joi.alternatives([
223
    Joi.string().hostname(),
224
    Joi.array().items(Joi.string().hostname()).min(1)
225
]);
226
 
227
 
228
internals.route = Joi.object({
229
    method: Joi.string().regex(/^[a-zA-Z0-9!#\$%&'\*\+\-\.^_`\|~]+$/).required(),
230
    path: Joi.string().required(),
231
    vhost: internals.vhost,
232
    handler: Joi.any(),                         // Validated in routeConfig
233
    config: Joi.alternatives([
234
        Joi.object(),
235
        Joi.func()
236
    ]).allow(null)
237
});
238
 
239
 
240
internals.pre = [
241
    Joi.string(),
242
    Joi.func(),
243
    Joi.object({
244
        method: Joi.alternatives(Joi.string(), Joi.func()).required(),
245
        assign: Joi.string(),
246
        mode: Joi.string().valid('serial', 'parallel'),
247
        failAction: Joi.string().valid('error', 'log', 'ignore')
248
    })
249
];
250
 
251
 
252
internals.routeConfig = internals.routeBase.keys({
253
    id: Joi.string(),
254
    isInternal: Joi.boolean(),
255
    pre: Joi.array().items(internals.pre.concat(Joi.array().items(internals.pre).min(1))),
256
    handler: [
257
        Joi.func(),
258
        Joi.string(),
259
        Joi.object().length(1)
260
    ],
261
    description: Joi.string(),
262
    notes: [
263
        Joi.string(),
264
        Joi.array().items(Joi.string())
265
    ],
266
    tags: [
267
        Joi.string(),
268
        Joi.array().items(Joi.string())
269
    ]
270
});
271
 
272
 
273
internals.cacheConfig = Joi.object({
274
    name: Joi.string().invalid('_default'),
275
    partition: Joi.string(),
276
    shared: Joi.boolean(),
277
    engine: Joi.alternatives([
278
        Joi.object(),
279
        Joi.func()
280
    ])
281
        .required()
282
}).unknown();
283
 
284
 
285
internals.cache = Joi.array().items(internals.cacheConfig, Joi.func()).min(1).single();
286
 
287
 
288
internals.cachePolicy = Joi.object({
289
    cache: Joi.string().allow(null).allow(''),
290
    segment: Joi.string(),
291
    shared: Joi.boolean()
292
})
293
    .options({ allowUnknown: true });               // Catbox validates other keys
294
 
295
 
296
internals.method = Joi.object({
297
    bind: Joi.object().allow(null),
298
    generateKey: Joi.func(),
299
    cache: internals.cachePolicy,
300
    callback: Joi.boolean()
301
});
302
 
303
 
304
internals.methodObject = Joi.object({
305
    name: Joi.string().required(),
306
    method: Joi.func().required(),
307
    options: Joi.object()
308
});
309
 
310
 
311
internals.register = Joi.object({
312
    once: Joi.boolean(),
313
    routes: Joi.object({
314
        prefix: Joi.string().regex(/^\/.+/),
315
        vhost: internals.vhost
316
    })
317
        .default({}),
318
    select: Joi.array().items(Joi.string()).single()
319
});
320
 
321
 
322
internals.plugin = internals.register.keys({
323
    register: Joi.func().keys({
324
        attributes: Joi.object({
325
            pkg: Joi.object({
326
                name: Joi.string(),
327
                version: Joi.string().default('0.0.0')
328
            })
329
                .unknown()
330
                .default({
331
                    version: '0.0.0'
332
                }),
333
            name: Joi.string()
334
                .when('pkg.name', { is: Joi.exist(), otherwise: Joi.required() }),
335
            version: Joi.string(),
336
            multiple: Joi.boolean().default(false),
337
            dependencies: Joi.array().items(Joi.string()).single(),
338
            connections: Joi.boolean().default(true),
339
            once: Joi.boolean().valid(true)
340
        })
341
            .required()
342
            .unknown()
343
    })
344
        .required(),
345
    options: Joi.any()
346
})
347
    .without('once', 'options')
348
    .unknown();