OLD | NEW |
(Empty) | |
| 1 // Copyright (c) 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/browser/policy/policy_schema.h" |
| 6 |
| 7 #include "base/compiler_specific.h" |
| 8 #include "base/logging.h" |
| 9 #include "base/stl_util.h" |
| 10 #include "chrome/common/json_schema/json_schema_constants.h" |
| 11 #include "chrome/common/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 |