OLD | NEW |
| (Empty) |
1 // Copyright 2013 The Chromium Authors. All rights reserved. | |
2 // Use of this source code is governed by a BSD-style license that can be | |
3 // found in the LICENSE file. | |
4 | |
5 #include "chrome/common/policy/policy_schema.h" | |
6 | |
7 #include "base/compiler_specific.h" | |
8 #include "base/logging.h" | |
9 #include "base/stl_util.h" | |
10 #include "components/json_schema/json_schema_constants.h" | |
11 #include "components/json_schema/json_schema_validator.h" | |
12 | |
13 namespace policy { | |
14 | |
15 namespace { | |
16 | |
17 const char kJSONSchemaVersion[] = "http://json-schema.org/draft-03/schema#"; | |
18 | |
19 // Describes the properties of a TYPE_DICTIONARY policy schema. | |
20 class DictionaryPolicySchema : public PolicySchema { | |
21 public: | |
22 static scoped_ptr<PolicySchema> Parse(const base::DictionaryValue& schema, | |
23 std::string* error); | |
24 | |
25 virtual ~DictionaryPolicySchema(); | |
26 | |
27 virtual const PolicySchemaMap* GetProperties() const OVERRIDE; | |
28 virtual const PolicySchema* GetSchemaForAdditionalProperties() const OVERRIDE; | |
29 | |
30 private: | |
31 DictionaryPolicySchema(); | |
32 | |
33 PolicySchemaMap properties_; | |
34 scoped_ptr<PolicySchema> additional_properties_; | |
35 | |
36 DISALLOW_COPY_AND_ASSIGN(DictionaryPolicySchema); | |
37 }; | |
38 | |
39 // Describes the items of a TYPE_LIST policy schema. | |
40 class ListPolicySchema : public PolicySchema { | |
41 public: | |
42 static scoped_ptr<PolicySchema> Parse(const base::DictionaryValue& schema, | |
43 std::string* error); | |
44 | |
45 virtual ~ListPolicySchema(); | |
46 | |
47 virtual const PolicySchema* GetSchemaForItems() const OVERRIDE; | |
48 | |
49 private: | |
50 ListPolicySchema(); | |
51 | |
52 scoped_ptr<PolicySchema> items_schema_; | |
53 | |
54 DISALLOW_COPY_AND_ASSIGN(ListPolicySchema); | |
55 }; | |
56 | |
57 bool SchemaTypeToValueType(const std::string& type_string, | |
58 base::Value::Type* type) { | |
59 // Note: "any" is not an accepted type. | |
60 static const struct { | |
61 const char* schema_type; | |
62 base::Value::Type value_type; | |
63 } kSchemaToValueTypeMap[] = { | |
64 { json_schema_constants::kArray, base::Value::TYPE_LIST }, | |
65 { json_schema_constants::kBoolean, base::Value::TYPE_BOOLEAN }, | |
66 { json_schema_constants::kInteger, base::Value::TYPE_INTEGER }, | |
67 { json_schema_constants::kNull, base::Value::TYPE_NULL }, | |
68 { json_schema_constants::kNumber, base::Value::TYPE_DOUBLE }, | |
69 { json_schema_constants::kObject, base::Value::TYPE_DICTIONARY }, | |
70 { json_schema_constants::kString, base::Value::TYPE_STRING }, | |
71 }; | |
72 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(kSchemaToValueTypeMap); ++i) { | |
73 if (kSchemaToValueTypeMap[i].schema_type == type_string) { | |
74 *type = kSchemaToValueTypeMap[i].value_type; | |
75 return true; | |
76 } | |
77 } | |
78 return false; | |
79 } | |
80 | |
81 scoped_ptr<PolicySchema> ParseSchema(const base::DictionaryValue& schema, | |
82 std::string* error) { | |
83 std::string type_string; | |
84 if (!schema.GetString(json_schema_constants::kType, &type_string)) { | |
85 *error = "The schema type must be declared."; | |
86 return scoped_ptr<PolicySchema>(); | |
87 } | |
88 | |
89 base::Value::Type type = base::Value::TYPE_NULL; | |
90 if (!SchemaTypeToValueType(type_string, &type)) { | |
91 *error = "The \"any\" type can't be used."; | |
92 return scoped_ptr<PolicySchema>(); | |
93 } | |
94 | |
95 switch (type) { | |
96 case base::Value::TYPE_DICTIONARY: | |
97 return DictionaryPolicySchema::Parse(schema, error); | |
98 case base::Value::TYPE_LIST: | |
99 return ListPolicySchema::Parse(schema, error); | |
100 default: | |
101 return make_scoped_ptr(new PolicySchema(type)); | |
102 } | |
103 } | |
104 | |
105 DictionaryPolicySchema::DictionaryPolicySchema() | |
106 : PolicySchema(base::Value::TYPE_DICTIONARY) {} | |
107 | |
108 DictionaryPolicySchema::~DictionaryPolicySchema() { | |
109 STLDeleteValues(&properties_); | |
110 } | |
111 | |
112 const PolicySchemaMap* DictionaryPolicySchema::GetProperties() const { | |
113 return &properties_; | |
114 } | |
115 | |
116 const PolicySchema* | |
117 DictionaryPolicySchema::GetSchemaForAdditionalProperties() const { | |
118 return additional_properties_.get(); | |
119 } | |
120 | |
121 // static | |
122 scoped_ptr<PolicySchema> DictionaryPolicySchema::Parse( | |
123 const base::DictionaryValue& schema, | |
124 std::string* error) { | |
125 scoped_ptr<DictionaryPolicySchema> dict_schema(new DictionaryPolicySchema()); | |
126 | |
127 const base::DictionaryValue* dict = NULL; | |
128 const base::DictionaryValue* properties = NULL; | |
129 if (schema.GetDictionary(json_schema_constants::kProperties, &properties)) { | |
130 for (base::DictionaryValue::Iterator it(*properties); | |
131 !it.IsAtEnd(); it.Advance()) { | |
132 // This should have been verified by the JSONSchemaValidator. | |
133 CHECK(it.value().GetAsDictionary(&dict)); | |
134 scoped_ptr<PolicySchema> sub_schema = ParseSchema(*dict, error); | |
135 if (!sub_schema) | |
136 return scoped_ptr<PolicySchema>(); | |
137 dict_schema->properties_[it.key()] = sub_schema.release(); | |
138 } | |
139 } | |
140 | |
141 if (schema.GetDictionary(json_schema_constants::kAdditionalProperties, | |
142 &dict)) { | |
143 scoped_ptr<PolicySchema> sub_schema = ParseSchema(*dict, error); | |
144 if (!sub_schema) | |
145 return scoped_ptr<PolicySchema>(); | |
146 dict_schema->additional_properties_ = sub_schema.Pass(); | |
147 } | |
148 | |
149 return dict_schema.PassAs<PolicySchema>(); | |
150 } | |
151 | |
152 ListPolicySchema::ListPolicySchema() | |
153 : PolicySchema(base::Value::TYPE_LIST) {} | |
154 | |
155 ListPolicySchema::~ListPolicySchema() {} | |
156 | |
157 const PolicySchema* ListPolicySchema::GetSchemaForItems() const { | |
158 return items_schema_.get(); | |
159 } | |
160 | |
161 scoped_ptr<PolicySchema> ListPolicySchema::Parse( | |
162 const base::DictionaryValue& schema, | |
163 std::string* error) { | |
164 const base::DictionaryValue* dict = NULL; | |
165 if (!schema.GetDictionary(json_schema_constants::kItems, &dict)) { | |
166 *error = "Arrays must declare a single schema for their items."; | |
167 return scoped_ptr<PolicySchema>(); | |
168 } | |
169 scoped_ptr<PolicySchema> items_schema = ParseSchema(*dict, error); | |
170 if (!items_schema) | |
171 return scoped_ptr<PolicySchema>(); | |
172 | |
173 scoped_ptr<ListPolicySchema> list_schema(new ListPolicySchema()); | |
174 list_schema->items_schema_ = items_schema.Pass(); | |
175 return list_schema.PassAs<PolicySchema>(); | |
176 } | |
177 | |
178 } // namespace | |
179 | |
180 PolicySchema::PolicySchema(base::Value::Type type) | |
181 : type_(type) {} | |
182 | |
183 PolicySchema::~PolicySchema() {} | |
184 | |
185 const PolicySchemaMap* PolicySchema::GetProperties() const { | |
186 NOTREACHED(); | |
187 return NULL; | |
188 } | |
189 | |
190 const PolicySchema* PolicySchema::GetSchemaForAdditionalProperties() const { | |
191 NOTREACHED(); | |
192 return NULL; | |
193 } | |
194 | |
195 const PolicySchema* PolicySchema::GetSchemaForProperty( | |
196 const std::string& key) const { | |
197 const PolicySchemaMap* properties = GetProperties(); | |
198 PolicySchemaMap::const_iterator it = properties->find(key); | |
199 return it == properties->end() ? GetSchemaForAdditionalProperties() | |
200 : it->second; | |
201 } | |
202 | |
203 const PolicySchema* PolicySchema::GetSchemaForItems() const { | |
204 NOTREACHED(); | |
205 return NULL; | |
206 } | |
207 | |
208 // static | |
209 scoped_ptr<PolicySchema> PolicySchema::Parse(const std::string& content, | |
210 std::string* error) { | |
211 // Validate as a generic JSON schema. | |
212 scoped_ptr<base::DictionaryValue> dict = | |
213 JSONSchemaValidator::IsValidSchema(content, error); | |
214 if (!dict) | |
215 return scoped_ptr<PolicySchema>(); | |
216 | |
217 // Validate the schema version. | |
218 std::string string_value; | |
219 if (!dict->GetString(json_schema_constants::kSchema, &string_value) || | |
220 string_value != kJSONSchemaVersion) { | |
221 *error = "Must declare JSON Schema v3 version in \"$schema\"."; | |
222 return scoped_ptr<PolicySchema>(); | |
223 } | |
224 | |
225 // Validate the main type. | |
226 if (!dict->GetString(json_schema_constants::kType, &string_value) || | |
227 string_value != json_schema_constants::kObject) { | |
228 *error = | |
229 "The main schema must have a type attribute with \"object\" value."; | |
230 return scoped_ptr<PolicySchema>(); | |
231 } | |
232 | |
233 // Checks for invalid attributes at the top-level. | |
234 if (dict->HasKey(json_schema_constants::kAdditionalProperties) || | |
235 dict->HasKey(json_schema_constants::kPatternProperties)) { | |
236 *error = "\"additionalProperties\" and \"patternProperties\" are not " | |
237 "supported at the main schema."; | |
238 return scoped_ptr<PolicySchema>(); | |
239 } | |
240 | |
241 return ParseSchema(*dict, error); | |
242 } | |
243 | |
244 } // namespace policy | |
OLD | NEW |