using System; using System.Collections.Generic; using System.Net; using JetBrains.Annotations; using Utf8Json; using Webserver.Permissions; namespace Webserver.WebAPI.APIs.Permissions { [UsedImplicitly] public class WebModules : AbsRestApi { private const string propertyModule = "module"; private const string propertyPermissionLevelGlobal = "permissionLevelGlobal"; private const string propertyPermissionLevelPerMethod = "permissionLevelPerMethod"; private const string propertyIsDefault = "isDefault"; private static readonly byte[] jsonKeyModule = JsonWriter.GetEncodedPropertyNameWithBeginObject (propertyModule); private static readonly byte[] jsonKeyPermissionLevelGlobal = JsonWriter.GetEncodedPropertyNameWithPrefixValueSeparator (propertyPermissionLevelGlobal); private static readonly byte[] jsonKeyPermissionLevelPerMethod = JsonWriter.GetEncodedPropertyNameWithPrefixValueSeparator (propertyPermissionLevelPerMethod); private static readonly byte[] jsonKeyIsDefault = JsonWriter.GetEncodedPropertyNameWithPrefixValueSeparator (propertyIsDefault); private static readonly byte[][] jsonMethodNameKeys; static WebModules () { jsonMethodNameKeys = new byte[(int)ERequestMethod.Count][]; for (int i = 0; i < jsonMethodNameKeys.Length; i++) { ERequestMethod method = (ERequestMethod)i; jsonMethodNameKeys [i] = JsonWriter.GetEncodedPropertyName (method.ToStringCached ()); } } private static AdminWebModules ModulesInstance => AdminWebModules.Instance; protected override void HandleRestGet (RequestContext _context) { string id = _context.RequestPath; PrepareEnvelopedResult (out JsonWriter writer); if (string.IsNullOrEmpty (id)) { writer.WriteBeginArray (); bool first = true; foreach (AdminWebModules.WebModule module in ModulesInstance.GetModules ()) { if (!first) { writer.WriteValueSeparator (); } first = false; writeModuleJson (ref writer, module); } writer.WriteEndArray (); SendEnvelopedResult (_context, ref writer); return; } writer.WriteRaw (WebUtils.JsonEmptyData); SendEnvelopedResult (_context, ref writer, HttpStatusCode.BadRequest); } private void writeModuleJson (ref JsonWriter _writer, AdminWebModules.WebModule _module) { _writer.WriteRaw (jsonKeyModule); _writer.WriteString (_module.Name); _writer.WriteRaw (jsonKeyPermissionLevelGlobal); _writer.WriteInt32 (_module.LevelGlobal); _writer.WriteRaw (jsonKeyPermissionLevelPerMethod); _writer.WriteBeginObject (); if (_module.LevelPerMethod != null) { bool first = true; for (int iMethod = 0; iMethod < _module.LevelPerMethod.Length; iMethod++) { int methodLevel = _module.LevelPerMethod [iMethod]; if (methodLevel == AdminWebModules.MethodLevelNotSupported) { continue; } if (!first) { _writer.WriteValueSeparator (); } first = false; _writer.WriteRaw (jsonMethodNameKeys [iMethod]); if (methodLevel == AdminWebModules.MethodLevelInheritGlobal) { _writer.WriteString (AdminWebModules.MethodLevelInheritKeyword); } else { _writer.WriteInt32 (methodLevel); } } } _writer.WriteEndObject (); _writer.WriteRaw (jsonKeyIsDefault); _writer.WriteBoolean (_module.IsDefault); _writer.WriteEndObject (); } protected override void HandleRestPost (RequestContext _context, IDictionary _jsonInput, byte[] _jsonInputData) { string id = _context.RequestPath; if (string.IsNullOrEmpty (id)) { SendEmptyResponse (_context, HttpStatusCode.BadRequest, _jsonInputData, EApiErrorCode.NO_MODULE); return; } if (!AdminWebModules.Instance.IsKnownModule (id)) { SendEmptyResponse (_context, HttpStatusCode.BadRequest, _jsonInputData, EApiErrorCode.INVALID_MODULE); return; } AdminWebModules.WebModule module = AdminWebModules.Instance.GetModule (id); if (_jsonInput.ContainsKey (propertyPermissionLevelGlobal)) { if (!JsonCommons.TryGetJsonField (_jsonInput, propertyPermissionLevelGlobal, out int permissionLevelGlobal)) { SendEmptyResponse (_context, HttpStatusCode.BadRequest, _jsonInputData, EApiErrorCode.INVALID_PERMISSION_LEVEL_GLOBAL); return; } module = module.SetLevelGlobal (permissionLevelGlobal); } if (_jsonInput.TryGetValue (propertyPermissionLevelPerMethod, out object perLevelField)) { if (perLevelField is not IDictionary perLevelObj) { SendEmptyResponse (_context, HttpStatusCode.BadRequest, _jsonInputData, EApiErrorCode.INVALID_PERMISSION_LEVEL_PER_METHOD_PROPERTY); return; } foreach ((string property, object valueObj) in perLevelObj) { if (!EnumUtils.TryParse (property, out ERequestMethod method, true)) { SendEmptyResponse (_context, HttpStatusCode.BadRequest, _jsonInputData, EApiErrorCode.INVALID_METHOD_NAME); return; } if (module.LevelPerMethod == null || module.LevelPerMethod [(int)method] == AdminWebModules.MethodLevelNotSupported) { SendEmptyResponse (_context, HttpStatusCode.BadRequest, _jsonInputData, EApiErrorCode.UNSUPPORTED_METHOD); return; } int permissionLevel; if (valueObj is string valueString) { if (!valueString.EqualsCaseInsensitive (AdminWebModules.MethodLevelInheritKeyword)) { SendEmptyResponse (_context, HttpStatusCode.BadRequest, _jsonInputData, EApiErrorCode.INVALID_PERMISSION_STRING); return; } permissionLevel = AdminWebModules.MethodLevelInheritGlobal; } else if (valueObj is double valueDbl) { try { permissionLevel = (int)valueDbl; } catch (Exception) { SendEmptyResponse (_context, HttpStatusCode.BadRequest, _jsonInputData, EApiErrorCode.INVALID_PERMISSION_VALUE); return; } } else { SendEmptyResponse (_context, HttpStatusCode.BadRequest, _jsonInputData, EApiErrorCode.INVALID_PERMISSION_VALUE_TYPE); return; } module = module.SetLevelForMethod (method, permissionLevel); } } ModulesInstance.AddModule (module); SendEmptyResponse (_context, HttpStatusCode.Created); } protected override void HandleRestDelete (RequestContext _context) { string id = _context.RequestPath; bool removed = ModulesInstance.RemoveModule (id); SendEmptyResponse (_context, removed ? HttpStatusCode.NoContent : HttpStatusCode.NotFound); } protected override bool AllowPostWithId => true; public override int[] DefaultMethodPermissionLevels () => new[] { AdminWebModules.MethodLevelNotSupported, AdminWebModules.MethodLevelInheritGlobal, AdminWebModules.MethodLevelInheritGlobal, AdminWebModules.MethodLevelNotSupported, AdminWebModules.MethodLevelInheritGlobal }; } }