1 /*
2  *  Copyright (C) 2005-2018 Team Kodi
3  *  This file is part of Kodi - https://kodi.tv
4  *
5  *  SPDX-License-Identifier: GPL-2.0-or-later
6  *  See LICENSES/README.md for more information.
7  */
8 
9 #pragma once
10 
11 #include "JSONUtils.h"
12 #include "utils/Variant.h"
13 
14 #include <limits>
15 #include <memory>
16 #include <string>
17 #include <vector>
18 
19 namespace JSONRPC
20 {
21   class JSONSchemaTypeDefinition;
22   typedef std::shared_ptr<JSONSchemaTypeDefinition> JSONSchemaTypeDefinitionPtr;
23 
24   /*!
25    \ingroup jsonrpc
26    \brief Class for a parameter of a
27    json rpc method.
28 
29    Represents a parameter of a defined
30    json rpc method and is used to verify
31    and extract the value of the parameter
32    in a method call.
33    */
34   class JSONSchemaTypeDefinition : protected CJSONUtils
35   {
36   public:
37     JSONSchemaTypeDefinition();
38 
39     bool Parse(const CVariant &value, bool isParameter = false);
40     JSONRPC_STATUS Check(const CVariant& value, CVariant& outputValue, CVariant& errorData) const;
41     void Print(bool isParameter, bool isGlobal, bool printDefault, bool printDescriptions, CVariant &output) const;
42     void ResolveReference();
43 
44     std::string missingReference;
45 
46     /*!
47      \brief Name of the parameter (for
48      by-name calls)
49      */
50     std::string name;
51 
52     /*!
53      \brief Id of the type (for
54      referenced types)
55      Renamed from "id" because of possible
56      issues with Objective-C.
57      */
58     std::string ID;
59 
60     /*!
61      \brief Referenced object
62      */
63     JSONSchemaTypeDefinitionPtr referencedType;
64 
65     /*!
66      \brief Whether the type has been set
67      based on the referenced type
68      */
69     bool referencedTypeSet = false;
70 
71     /*!
72      \brief Array of reference types
73      which are extended by this type.
74      */
75     std::vector<JSONSchemaTypeDefinitionPtr> extends;
76 
77     /*!
78      \brief Description of the parameter
79      */
80     std::string description;
81 
82     /*!
83      \brief JSON schema type of the parameter's value
84      */
85     JSONSchemaType type = AnyValue;
86 
87     /*!
88      \brief JSON schema type definitions in case
89      of a union type
90      */
91     std::vector<JSONSchemaTypeDefinitionPtr> unionTypes;
92 
93     /*!
94      \brief Whether or not the parameter is
95      optional
96      */
97     bool optional = true;
98 
99     /*!
100      \brief Default value of the parameter
101      (only needed when it is optional)
102      */
103     CVariant defaultValue;
104 
105     /*!
106      \brief Minimum value for Integer
107      or Number types
108      */
109     double minimum;
110 
111     /*!
112      \brief Maximum value for Integer or Number types
113      */
114     double maximum;
115 
116     /*!
117      \brief Whether to exclude the defined Minimum
118      value from the valid range or not
119      */
120     bool exclusiveMinimum = false;
121 
122     /*!
123      \brief  Whether to exclude the defined Maximum
124      value from the valid range or not
125      */
126     bool exclusiveMaximum = false;
127 
128     /*!
129      \brief Integer by which the value (of type
130      Integer) must be divisible without rest
131      */
132     unsigned int divisibleBy = 0;
133 
134     /*!
135      \brief Minimum length for String types
136      */
137     int minLength = -1;
138 
139     /*!
140      \brief Maximum length for String types
141      */
142     int maxLength = -1;
143 
144     /*!
145      \brief (Optional) List of allowed values
146      for the type
147      */
148     std::vector<CVariant> enums;
149 
150     /*!
151      \brief List of possible values in an array
152      */
153     std::vector<JSONSchemaTypeDefinitionPtr> items;
154 
155     /*!
156      \brief Minimum amount of items in the array
157      */
158     unsigned int minItems = 0;
159 
160     /*!
161      \brief Maximum amount of items in the array
162      */
163     unsigned int maxItems = 0;
164 
165     /*!
166      \brief Whether every value in the array
167      must be unique or not
168      */
169     bool uniqueItems = false;
170 
171     /*!
172      \brief List of json schema definitions for
173      additional items in an array with tuple
174      typing (defined schemas in "items")
175      */
176     std::vector<JSONSchemaTypeDefinitionPtr> additionalItems;
177 
178     /*!
179      \brief Maps a properties name to its
180      json schema type definition
181      */
182     class CJsonSchemaPropertiesMap
183     {
184     public:
185       CJsonSchemaPropertiesMap();
186 
187       void add(const JSONSchemaTypeDefinitionPtr& property);
188 
189       typedef std::map<std::string, JSONSchemaTypeDefinitionPtr>::const_iterator JSONSchemaPropertiesIterator;
190       JSONSchemaPropertiesIterator begin() const;
191       JSONSchemaPropertiesIterator find(const std::string& key) const;
192       JSONSchemaPropertiesIterator end() const;
193       unsigned int size() const;
194     private:
195       std::map<std::string, JSONSchemaTypeDefinitionPtr> m_propertiesmap;
196     };
197 
198     /*!
199      \brief List of properties of the parameter (only needed when the
200      parameter is an object)
201      */
202     CJsonSchemaPropertiesMap properties;
203 
204     /*!
205      \brief Whether the type can have additional properties
206      or not
207      */
208     bool hasAdditionalProperties = false;
209 
210     /*!
211      \brief Type definition for additional properties
212      */
213     JSONSchemaTypeDefinitionPtr additionalProperties;
214   };
215 
216   /*!
217    \ingroup jsonrpc
218    \brief Structure for a published json
219    rpc method.
220 
221    Represents a published json rpc method
222    and is used to verify an incoming json
223    rpc request against a defined method.
224    */
225   class JsonRpcMethod : protected CJSONUtils
226   {
227   public:
228     JsonRpcMethod();
229 
230     bool Parse(const CVariant &value);
231     JSONRPC_STATUS Check(const CVariant &requestParameters, ITransportLayer *transport, IClient *client, bool notification, MethodCall &methodCall, CVariant &outputParameters) const;
232 
233     std::string missingReference;
234 
235     /*!
236      \brief Name of the represented method
237      */
238     std::string name;
239     /*!
240      \brief Pointer tot he implementation
241      of the represented method
242      */
243     MethodCall method;
244     /*!
245      \brief Definition of the type of
246      request/response
247      */
248     TransportLayerCapability transportneed = Response;
249     /*!
250      \brief Definition of the permissions needed
251      to execute the method
252      */
253     OperationPermission permission = ReadData;
254     /*!
255      \brief Description of the method
256      */
257     std::string description;
258     /*!
259      \brief List of accepted parameters
260      */
261     std::vector<JSONSchemaTypeDefinitionPtr> parameters;
262     /*!
263      \brief Definition of the return value
264      */
265     JSONSchemaTypeDefinitionPtr returns;
266 
267   private:
268     bool parseParameter(const CVariant& value, const JSONSchemaTypeDefinitionPtr& parameter);
269     bool parseReturn(const CVariant &value);
270     static JSONRPC_STATUS checkParameter(const CVariant& requestParameters,
271                                          const JSONSchemaTypeDefinitionPtr& type,
272                                          unsigned int position,
273                                          CVariant& outputParameters,
274                                          unsigned int& handled,
275                                          CVariant& errorData);
276   };
277 
278   /*!
279    \ingroup jsonrpc
280    \brief Structure mapping a json rpc method
281    definition to an actual method implementation.
282    */
283   typedef struct
284   {
285     /*!
286      \brief Name of the json rpc method.
287      */
288     std::string name;
289     /*!
290      \brief Pointer to the actual
291      implementation of the json rpc
292      method.
293      */
294     MethodCall method;
295   } JsonRpcMethodMap;
296 
297   /*!
298    \ingroup jsonrpc
299    \brief Helper class for json schema service descriptor based
300    service descriptions for the json rpc API
301 
302    Provides static functions to parse a complete json schema
303    service descriptor of a published service containing json rpc
304    methods, print the json schema service descriptor representation
305    into a string (mainly for output purposes) and evaluate and verify
306    parameters provided in a call to one of the publish json rpc methods
307    against a parameter definition parsed from a json schema service
308    descriptor.
309    */
310   class CJSONServiceDescription : public CJSONUtils
311   {
312     friend class JSONSchemaTypeDefinition;
313     friend class JsonRpcMethod;
314   public:
315     /*!
316      \brief Parses the given json schema description and evaluates
317      and stores the defined type
318      \param jsonType json schema description to parse
319      \return True if the json schema description has been parsed successfully otherwise false
320      */
321     static bool AddType(const std::string &jsonType);
322 
323     /*!
324      \brief Parses the given json schema description and evaluates
325      and stores the defined method
326      \param jsonMethod json schema description to parse
327      \param method pointer to the implementation
328      \return True if the json schema description has been parsed successfully otherwise false
329      */
330     static bool AddMethod(const std::string &jsonMethod, MethodCall method);
331 
332     /*!
333      \brief Parses the given json schema description and evaluates
334      and stores the defined builtin method
335      \param jsonMethod json schema description to parse
336      \return True if the json schema description has been parsed successfully otherwise false
337      */
338     static bool AddBuiltinMethod(const std::string &jsonMethod);
339 
340     /*!
341      \brief Parses the given json schema description and evaluates
342      and stores the defined notification
343      \param jsonNotification json schema description to parse
344      \return True if the json schema description has been parsed successfully otherwise false
345      */
346     static bool AddNotification(const std::string &jsonNotification);
347 
348     static bool AddEnum(const std::string &name, const std::vector<CVariant> &values, CVariant::VariantType type = CVariant::VariantTypeNull, const CVariant &defaultValue = CVariant::ConstNullVariant);
349     static bool AddEnum(const std::string &name, const std::vector<std::string> &values);
350     static bool AddEnum(const std::string &name, const std::vector<int> &values);
351 
352     /*!
353      \brief Gets the version of the json
354      schema description
355      \return Version of the json schema description
356      */
357     static const char* GetVersion();
358 
359     /*!
360      \brief Prints the json schema description into the given result object
361      \param result Object into which the json schema description is printed
362      \param transport Transport layer capabilities
363      \param client Client requesting a print
364      \param printDescriptions Whether to print descriptions or not
365      \param printMetadata Whether to print XBMC specific data or not
366      \param filterByTransport Whether to filter by transport or not
367      */
368     static JSONRPC_STATUS Print(CVariant &result, ITransportLayer *transport, IClient *client, bool printDescriptions = true, bool printMetadata = false, bool filterByTransport = true, const std::string &filterByName = "", const std::string &filterByType = "", bool printReferences = true);
369 
370     /*!
371      \brief Checks the given parameters from the request against the
372      json schema description for the given method
373      \param method Called method
374      \param requestParameters Parameters from the request
375      \param client Client who sent the request
376      \param notification Whether the request was sent as a notification or not
377      \param methodCall Object which will contain the actual C/C++ method to be called
378      \param outputParameters Cleaned up parameter list
379      \return OK if the validation of the request succeeded otherwise an appropriate error code
380 
381      Checks if the given method is a valid json rpc method, if the client has the permission
382      to call this method, if the method can be called as a notification or not, assigns the
383      actual C/C++ implementation of the method to the "methodCall" parameter and checks the
384      given parameters from the request against the json schema description for the given method.
385      */
386     static JSONRPC_STATUS CheckCall(const char* method, const CVariant &requestParameters, ITransportLayer *transport, IClient *client, bool notification, MethodCall &methodCall, CVariant &outputParameters);
387 
388     static JSONSchemaTypeDefinitionPtr GetType(const std::string &identification);
389 
390     static void ResolveReferences();
391     static void Cleanup();
392 
393   private:
394     static bool prepareDescription(std::string &description, CVariant &descriptionObject, std::string &name);
395     static bool addMethod(const std::string &jsonMethod, MethodCall method);
396     static void parseHeader(const CVariant &descriptionObject);
397     static bool parseJSONSchemaType(const CVariant &value, std::vector<JSONSchemaTypeDefinitionPtr>& typeDefinitions, JSONSchemaType &schemaType, std::string &missingReference);
398     static void addReferenceTypeDefinition(const JSONSchemaTypeDefinitionPtr& typeDefinition);
399     static void removeReferenceTypeDefinition(const std::string &typeID);
400 
401     static void getReferencedTypes(const JSONSchemaTypeDefinitionPtr& type,
402                                    std::vector<std::string>& referencedTypes);
403 
404     class CJsonRpcMethodMap
405     {
406     public:
407       CJsonRpcMethodMap();
408 
409       void add(const JsonRpcMethod &method);
410 
411       typedef std::map<std::string, JsonRpcMethod>::const_iterator JsonRpcMethodIterator;
412       JsonRpcMethodIterator begin() const;
413       JsonRpcMethodIterator find(const std::string& key) const;
414       JsonRpcMethodIterator end() const;
415 
416       void clear();
417     private:
418       std::map<std::string, JsonRpcMethod> m_actionmap;
419     };
420 
421     static CJsonRpcMethodMap m_actionMap;
422     static std::map<std::string, JSONSchemaTypeDefinitionPtr> m_types;
423     static std::map<std::string, CVariant> m_notifications;
424     static JsonRpcMethodMap m_methodMaps[];
425 
426     typedef enum SchemaDefinition
427     {
428       SchemaDefinitionType,
429       SchemaDefinitionMethod
430     } SchemaDefinition;
431 
432     typedef struct IncompleteSchemaDefinition
433     {
434       std::string Schema;
435       SchemaDefinition Type;
436       MethodCall Method;
437     } IncompleteSchemaDefinition;
438 
439     typedef std::map<std::string, std::vector<IncompleteSchemaDefinition> > IncompleteSchemaDefinitionMap;
440     static IncompleteSchemaDefinitionMap m_incompleteDefinitions;
441   };
442 }
443