Ejemplo n.º 1
0
        /// <summary>
        /// Helper method used to send data stored as a resource under the webres folder (namespace).
        /// </summary>
        /// <param name="target">The name of the resource in the webres folder/namespace.</param>
        /// <param name="state">Pass-through parameter.</param>
        /// <param name="request">Pass-through parameter.</param>
        /// <param name="body">Pass-through parameter.</param>
        /// <param name="encoder">Pass-through parameter.</param>
        /// <returns>A task object which may or may not be completed already. This also may need to be returned as a dependency of the handler completion.</returns>
        private static async Task <Task> StaticRoute(
            string target,
            ServerHandler state,
            HTTPRequest request,
            Stream body,
            IProxyHTTPEncoder encoder)
        {
            await Util.ReadStreamUntilEndAndDiscardDataAsync(body);

#if USE_SOURCE_DIRECTORY_WEBRES
            var strm = File.OpenRead(
                Path.Combine(
                    @"/home/kmcguire/extra/old/source/repos/MDACSDatabase/MDACSDatabase/webres",
                    target
                    )
                );
#else
            var strm = Assembly.GetExecutingAssembly().GetManifestResourceStream($"MDACSDatabase.webres.{target}");

            if (strm == null)
            {
                return(await encoder.Response(404, "Not Found")
                       .CacheControl("no-cache, no-store, must-revalidate")
                       .SendNothing());
            }
#endif
            return(await encoder.Response(200, "OK")
                   .ContentType_GuessFromFileName(target)
                   .CacheControl("public, max-age=0")
                   .SendStream(strm));
        }
Ejemplo n.º 2
0
        public async Task <Task> ServeData(string dataName, IProxyHTTPEncoder encoder)
        {
            var dataNameSanitized = SanitizeDataName(dataName);
            var fullPath          = Path.Combine(cfg.web_resources_path, dataNameSanitized);

            FileStream fp;

            try {
                fp = File.OpenRead(fullPath);
            } catch (FileNotFoundException) {
                return(encoder.Response(404, "Not Found")
                       .ContentType("text/plain")
                       .CacheControlDoNotCache()
                       .SendString("Not Found"));
            } catch (Exception ex) {
                return(encoder.Response(500, "Internal Error")
                       .ContentType("text/plain")
                       .CacheControlDoNotCache()
                       .SendString(ex.ToString()));
            }

            return(await encoder.Response(200, "OK")
                   .ContentType_GuessFromFileName(dataName)
                   .CacheControlDoNotCache()
                   .SendStream(fp));
        }
Ejemplo n.º 3
0
        public static async Task <Task> UserList(
            ServerState state,
            HTTPRequest request,
            Stream body,
            IProxyHTTPEncoder encoder)
        {
            var msg = await Util.ReadJsonObjectFromStreamAsync <Msg>(body, 1024);

            var(user, req) = state.AuthenticateMessage <JObject>(msg);

            if (user == null)
            {
                return(await encoder.Response(403, "The user list request was denied due to an authentication failure.")
                       .ContentType("text/plain")
                       .CacheControlDoNotCache()
                       .SendNothing());
            }


            var users = state.GetUserList();

            return(await encoder.Response(200, "OK")
                   .ContentType_JSON()
                   .SendJsonFromObject(state.GetUserList()));
        }
Ejemplo n.º 4
0
 public QuickResponse(int code, string text, IProxyHTTPEncoder proxy)
 {
     response_code = code;
     response_text = text;
     header        = new Dictionary <string, string>();
     this.proxy    = proxy;
 }
Ejemplo n.º 5
0
        public static async Task <Task> Utility(
            ServerHandler state,
            HTTPRequest request,
            Stream body,
            IProxyHTTPEncoder encoder)
        {
            await Util.ReadStreamUntilEndAndDiscardDataAsync(body);

            return(await StaticRoute(request.query_string, state, request, body, encoder));
        }
Ejemplo n.º 6
0
        public static async Task <Task> Index(
            ServerHandler state,
            HTTPRequest request,
            Stream body,
            IProxyHTTPEncoder encoder)
        {
            await Util.ReadStreamUntilEndAndDiscardDataAsync(body);

            return(await StaticRoute("index.html", state, request, body, encoder));
        }
Ejemplo n.º 7
0
        public static async Task <Task> Challenge(
            ServerState state,
            HTTPRequest request,
            Stream body,
            IProxyHTTPEncoder encoder)
        {
            await Util.ReadStreamUntilEndAndDiscardDataAsync(body);

            var challenge = state.GetChallenge();

            return(await encoder.Response(200, "OK")
                   .ContentType_JSON()
                   .SendString(
                       JsonConvert.SerializeObject(new AuthChallengeResponse()
            {
                challenge = challenge,
            }
                                                   )
                       ));
        }
Ejemplo n.º 8
0
        public static async Task <Task> UserDelete(
            ServerState state,
            HTTPRequest request,
            Stream body,
            IProxyHTTPEncoder encoder)
        {
            var msg = await Util.ReadJsonObjectFromStreamAsync <Msg>(body, 1024);

            var(user, req) = state.AuthenticateMessage <AuthUserDeleteRequest>(msg);

            if (user == null)
            {
                return(await encoder.Response(403, "Authentication failed for the user used.")
                       .ContentType("text/plain")
                       .CacheControlDoNotCache()
                       .SendNothing());
            }

            if (!user.admin)
            {
                return(await encoder.Response(403, "Disallowed delete of user by non-administrator.")
                       .ContentType("text/plain")
                       .CacheControlDoNotCache()
                       .SendNothing());
            }

            if (!await state.DeleteUser(req.username))
            {
                return(await encoder.Response(500, "The delete user command failed on the server.")
                       .ContentType("text/plain")
                       .CacheControlDoNotCache()
                       .SendNothing());
            }

            return(await encoder.Response(200, "OK")
                   .ContentType("text/plain")
                   .CacheControlDoNotCache()
                   .SendNothing());
        }
Ejemplo n.º 9
0
        public static async Task <Task> UserSet(
            ServerState state,
            HTTPRequest request,
            Stream body,
            IProxyHTTPEncoder encoder)
        {
            var msg = await Util.ReadJsonObjectFromStreamAsync <Msg>(body, 1024);

            var(user, req) = state.AuthenticateMessage <AuthUserSetRequest>(msg);

            if (user == null)
            {
                return(await encoder.Response(403, "Authentication based on user failed.")
                       .ContentType("text/plain")
                       .CacheControlDoNotCache()
                       .SendNothing());
            }

            if (!user.admin && user.user != req.user.user)
            {
                return(await encoder.Response(403, "Disallowed modification of another user.")
                       .ContentType("text/plain")
                       .CacheControlDoNotCache()
                       .SendNothing());
            }

            if (!await state.SetUser(req.user))
            {
                return(await encoder.Response(500, "The set user command failed to execute.")
                       .ContentType("text/plain")
                       .CacheControlDoNotCache()
                       .SendNothing());
            }

            return(await encoder.Response(200, "OK")
                   .ContentType("text/plain")
                   .CacheControlDoNotCache()
                   .SendNothing());
        }
Ejemplo n.º 10
0
        public static async Task <Task> VerifyPayload(
            ServerState state,
            HTTPRequest request,
            Stream body,
            IProxyHTTPEncoder encoder)
        {
            var req = await Util.ReadJsonObjectFromStreamAsync <AuthVerifyPayloadRequest>(body, 1024 * 1024);

            var user = state.VerifyPayload(req.challenge, req.chash, req.phash);

            if (user == null)
            {
                return(await encoder.Response(403, "Authentication based on user failed.").SendNothing());
            }

            var resp = new AuthCheckResponse()
            {
                payload = "",
                success = true,
                user    = user,
            };

            return(await encoder.Response(200, "OK").ContentType_JSON().SendJsonFromObject(resp));
        }
Ejemplo n.º 11
0
 public static async Task <Task> Utility(ServerCore core, HTTPRequest request, Stream body, IProxyHTTPEncoder encoder)
 {
     return(await core.ServeData(request.query_string, encoder));
 }
Ejemplo n.º 12
0
 public static async Task <Task> Index(ServerCore core, HTTPRequest request, Stream body, IProxyHTTPEncoder encoder)
 {
     return(await core.ServeData("index.html", encoder));
 }
Ejemplo n.º 13
0
        /// <summary>
        /// Performs higher-level interpretation of application layer data and provides that in a higher level form
        /// for consumption by the upper layers.
        /// </summary>
        /// <param name="header"></param>
        /// <param name="body"></param>
        /// <param name="encoder"></param>
        /// <returns></returns>
        /// <remarks>This implementation needs cleaning on variable names for query string processing.</remarks>
        public override async Task <Task> HandleRequest(Dictionary <String, String> header, Stream body, IProxyHTTPEncoder encoder)
        {
            var outheader = new Dictionary <String, String>();

            // Ensure the URL parameter actually exists instead of crashing.
            if (!header.ContainsKey("$url"))
            {
                outheader.Add("$response_code", "500");
                outheader.Add("$response_text", "ERROR");
                await encoder.WriteHeader(outheader);

                await encoder.BodyWriteSingleChunk("The request did not specify a URL.");

                return(Task.CompletedTask);
            }

            var    url             = header["$url"];
            var    url_absolute    = url;
            var    query_string    = new Dictionary <String, String>();
            String query_as_string = null;

            // Break down any query string into its key and value parts.
            if (url.IndexOf("?") > -1)
            {
                var qsndx = url.IndexOf("?");
                query_as_string = url.Substring(qsndx + 1);
                var qstring_parts = query_as_string.Split('&');

                foreach (var part in qstring_parts)
                {
                    var eqndx = part.IndexOf("=");

                    if (eqndx < 0)
                    {
                        query_string.Add(part, part);
                    }
                    else
                    {
                        query_string.Add(part.Substring(0, eqndx), part.Substring(eqndx + 1));
                    }
                }

                url_absolute = url.Substring(0, qsndx);
            }

            HTTPRequest request;

            switch (header["$method"].ToLower())
            {
            case "get":
                request.method = HTTPRequestMethod.GET;
                break;

            case "post":
                request.method = HTTPRequestMethod.POST;
                break;

            default:
                request.method = HTTPRequestMethod.UNKNOWN;
                break;
            }

            // Package everything up nice. Hide away the messy implementation details.
            request.internal_headers = header;
            request.query            = query_string;
            request.url          = url;
            request.url_absolute = url_absolute;
            request.query_string = query_as_string;

            return(await HandleRequest2(request, body, encoder));
        }
Ejemplo n.º 14
0
        /// <summary>
        /// Handles returning information about space/bytes usage of the database.
        /// </summary>
        /// <param name="shandler"></param>
        /// <param name="request"></param>
        /// <param name="body"></param>
        /// <param name="encoder"></param>
        /// <returns></returns>
        public static async Task <Task> Action(ServerHandler shandler, HTTPRequest request, Stream body, IProxyHTTPEncoder encoder)
        {
            var buf = new byte[512];
            int cnt;

            do
            {
                cnt = await body.ReadAsync(buf, 0, buf.Length);
            } while (cnt > 0);

            InternalVersonInfo ver_info;

            using (var strm = Assembly.GetExecutingAssembly().GetManifestResourceStream("MDACSDatabase.buildinfo.json"))
            {
                var json_data = await new StreamReader(strm).ReadToEndAsync();

                ver_info = JsonConvert.DeserializeObject <InternalVersonInfo>(json_data);
            }

            var resp = new VersionResponse()
            {
                version = ver_info.version,
            };

            await encoder.WriteQuickHeader(200, "OK");

            await encoder.BodyWriteSingleChunk(JsonConvert.SerializeObject(resp));

            return(Task.CompletedTask);
        }
Ejemplo n.º 15
0
        /// <summary>
        /// The function responsible for handling each request. This function can be implemented by subclassing
        /// of this class and using override. The function is provided with the request header, request body, and
        /// the response encoder which allows setting of headers and data if any.
        /// </summary>
        /// <param name="header"></param>
        /// <param name="body"></param>
        /// <param name="encoder"></param>
        /// <returns></returns>
        public virtual async Task <Task> HandleRequest(Dictionary <String, String> header, Stream body, IProxyHTTPEncoder encoder)
        {
            var outheader = new Dictionary <String, String>();

            outheader.Add("$response_code", "200");
            outheader.Add("$response_text", "OK");

            await encoder.WriteHeader(outheader);

            MemoryStream ms = new MemoryStream();

            byte[] something = Encoding.UTF8.GetBytes("hello world\n");

            ms.Write(something, 0, something.Length);
            ms.Write(something, 0, something.Length);
            ms.Write(something, 0, something.Length);
            ms.Write(something, 0, something.Length);
            ms.Write(something, 0, something.Length);

            ms.Position = 0;

            //await encoder.BodyWriteSingleChunk("response test body");
            await encoder.BodyWriteStream(ms);

            return(Task.CompletedTask);
        }
        public static async Task <Task> Action(ServerHandler shandler, HTTPRequest request, Stream body, IProxyHTTPEncoder encoder)
        {
            await MDACS.Server.Util.ReadStreamUntilEndAndDiscardDataAsync(body);

            var resp = new JObject();

            resp["dbUrl"]   = ".";
            resp["authUrl"] = shandler.auth_url;

            await encoder.WriteQuickHeader(200, "OK");

            await encoder.BodyWriteSingleChunk(JsonConvert.SerializeObject(resp));

            return(Task.CompletedTask);
        }
Ejemplo n.º 17
0
        /// <summary>
        /// Handles deleting existing data files. Requires authentication and a special privilege.
        /// </summary>
        /// <param name="shandler"></param>
        /// <param name="request"></param>
        /// <param name="body"></param>
        /// <param name="encoder"></param>
        /// <returns></returns>
        public static async Task <Task> Action(ServerHandler shandler, HTTPRequest request, Stream body, IProxyHTTPEncoder encoder)
        {
            var auth_resp = await Helpers.ReadMessageFromStreamAndAuthenticate(shandler, 1024 * 16, body);

            if (!auth_resp.success)
            {
                return(encoder.Response(403, "Denied").SendNothing());
            }

            if (!auth_resp.user.can_delete)
            {
                return(encoder.Response(403, "Denied").SendNothing());
            }

            var sreq = JsonConvert.DeserializeObject <DeleteRequest>(auth_resp.payload);

            var sid = sreq.sid;

            if (shandler.items.ContainsKey(sid))
            {
                var item = shandler.items[sid];

                try
                {
                    File.Delete(item.fqpath);
                } catch (Exception)
                {
                    await encoder.WriteQuickHeaderAndStringBody(
                        500, "Error", JsonConvert.SerializeObject(new DeleteResponse()
                    {
                        success = false,
                    })
                        );

                    return(Task.CompletedTask);
                }

                if (item.fqpath != null && item.fqpath.Length > 0)
                {
                    shandler.UsedSpaceSubtract((long)item.datasize);
                }

                item.fqpath = null;

                await shandler.WriteItemToJournal(item);
            }

            await encoder.WriteQuickHeaderAndStringBody(
                200, "Deleted", JsonConvert.SerializeObject(new DeleteResponse()
            {
                success = true,
            })
                );

            return(Task.CompletedTask);
        }
        public static async Task <Task> Action(ServerHandler shandler, HTTPRequest request, Stream body, IProxyHTTPEncoder encoder)
        {
            var auth = await Helpers.ReadMessageFromStreamAndAuthenticate(shandler, 1024 * 16, body);

            if (!auth.success)
            {
                return(encoder.Response(403, "Denied").SendNothing());
            }

            var req = JsonConvert.DeserializeObject <HandleBatchSingleOpsRequest>(auth.payload);

            var failed = new List <BatchSingleOp>();
            var tasks  = new List <Task <bool> >();

            foreach (var op in req.ops)
            {
                var sid        = op.sid;
                var field_name = op.field_name;

                if (!await shandler.FieldModificationValidForUser(auth.user, field_name))
                {
                    return(encoder.Response(403, $"Denied Change On Field {field_name}").SendNothing());
                }
            }

            foreach (var op in req.ops)
            {
                var sid        = op.sid;
                var field_name = op.field_name;
                var value      = op.value;

                lock (shandler.items)
                {
                    if (shandler.items.ContainsKey(sid))
                    {
                        try
                        {
                            var tmp   = shandler.items[sid];
                            var field = tmp.GetType().GetField(field_name);
                            field.SetValue(tmp, value.ToObject(field.FieldType));
                            tasks.Add(shandler.WriteItemToJournal(tmp));
                        }
                        catch (Exception ex)
                        {
                            //Logger.WriteDebugString(
                            //    $"Failed during batch single operation. The SID was {sid}. The field name was {field_name}. The value was {value}. The error was:\n{ex}"
                            //);
                            failed.Add(new BatchSingleOp()
                            {
                                field_name = field_name,
                                sid        = sid,
                                value      = value,
                            });
                        }
                    }
                    else
                    {
                        failed.Add(new BatchSingleOp()
                        {
                            field_name = field_name,
                            sid        = sid,
                            value      = value,
                        });
                    }
                }
            }

            Task.WaitAll(tasks.ToArray());

            var resp = new HandleBatchSingleOpsResponse();

            resp.success = true;
            resp.failed  = failed.ToArray();

            await encoder.Response(200, "OK")
            .CacheControlDoNotCache()
            .SendJsonFromObject(resp);

            return(Task.CompletedTask);
        }
Ejemplo n.º 19
0
        /// <summary>
        /// Handles returning information about space/bytes usage of the database.
        /// </summary>
        /// <param name="shandler"></param>
        /// <param name="request"></param>
        /// <param name="body"></param>
        /// <param name="encoder"></param>
        /// <returns></returns>
        public static async Task <Task> Action(ServerHandler shandler, HTTPRequest request, Stream body, IProxyHTTPEncoder encoder)
        {
            var auth_resp = await Helpers.ReadMessageFromStreamAndAuthenticate(shandler, 1024 * 16, body);

            if (!auth_resp.success)
            {
                throw new UnauthorizedException();
            }

            var resp = new JObject();

            resp["success"]    = true;
            resp["used_bytes"] = shandler.GetUsedSpace();
            resp["max_bytes"]  = shandler.GetMaxSpace();

            await encoder.WriteQuickHeader(200, "OK");

            await encoder.BodyWriteSingleChunk(JsonConvert.SerializeObject(resp));

            return(Task.CompletedTask);
        }
Ejemplo n.º 20
0
        /// <summary>
        /// The entry point for route handling. Provides common error response from exception propogation.
        /// </summary>
        /// <param name="request"></param>
        /// <param name="body"></param>
        /// <param name="encoder"></param>
        /// <returns>Asynchronous task object.</returns>
        public override async Task <Task> HandleRequest2(HTTPRequest request, Stream body, IProxyHTTPEncoder encoder)
        {
            try
            {
                Debug.WriteLine($"url={request.url}");

                if (!this.handlers.ContainsKey(request.url_absolute))
                {
                    await encoder.WriteQuickHeader(404, "Not Found");

                    await encoder.BodyWriteSingleChunk("The request resource is not avaliable.");

                    return(Task.CompletedTask);
                }

                return(await this.handlers[request.url_absolute](this.user_argument, request, body, encoder));
            }
            catch (Exception ex)
            {
                Console.WriteLine("==== EXCEPTION ====");
                Console.WriteLine(ex.Message);
                Console.WriteLine(ex.StackTrace);

                throw;
            }
        }
Ejemplo n.º 21
0
        public static async Task <Task> IsLoginValid(
            ServerState state,
            HTTPRequest request,
            Stream body,
            IProxyHTTPEncoder encoder)
        {
            var msg = await Util.ReadJsonObjectFromStreamAsync <Msg>(body, 1024);

            bool valid = false;

            User user;

            if (msg.payload == null || msg.auth.hash == null)
            {
                // Ensure the payload can never be accidentally used since this
                // authentication is without a payload hash.
                msg.payload = null;

                user = state.Verify(msg.auth.challenge, msg.auth.chash);

                if (user != null)
                {
                    valid = true;
                }
            }
            else
            {
                var payload_hash = BitConverter.ToString(
                    new SHA512Managed().ComputeHash(
                        Encoding.UTF8.GetBytes(msg.payload)
                        )
                    ).Replace("-", "").ToLower();

                user = state.VerifyPayload(
                    msg.auth.challenge,
                    msg.auth.chash,
                    payload_hash /* recompute it */
                    );

                if (user != null)
                {
                    valid = true;
                }
            }

            if (valid)
            {
                return(await encoder.Response(200, "Login Valid")
                       .CacheControlDoNotCache()
                       .ContentType_JSON()
                       .SendJsonFromObject(new AuthLoginValidResponse()
                {
                    success = true,
                    user = user,
                }));
            }
            else
            {
                return(await encoder.Response(403, "The login was not valid.")
                       .CacheControlDoNotCache()
                       .ContentType_JSON()
                       .SendJsonFromObject(new AuthLoginValidResponse()
                {
                    success = false,
                    user = null,
                }));
            }
        }
Ejemplo n.º 22
0
        public static async Task <Task> GetConfig(ServerCore core, HTTPRequest request, Stream body, IProxyHTTPEncoder encoder)
        {
            await MDACS.Server.Util.ReadStreamUntilEndAndDiscardDataAsync(body);

            var resp = new JObject();

            resp["dbUrl"]   = core.GetDatabaseUrl();
            resp["authUrl"] = core.GetAuthUrl();

            await encoder.WriteQuickHeader(200, "OK");

            await encoder.BodyWriteSingleChunk(JsonConvert.SerializeObject(resp));

            return(Task.CompletedTask);
        }
Ejemplo n.º 23
0
 /// <summary>
 /// Must be implemented by sub-class.
 /// </summary>
 /// <remarks>May come back and refactor this to use interfaces instead of subclases.</remarks>
 /// <param name="request"></param>
 /// <param name="body"></param>
 /// <param name="encoder"></param>
 /// <returns></returns>
 public virtual async Task <Task> HandleRequest2(HTTPRequest request, Stream body, IProxyHTTPEncoder encoder)
 {
     throw new Exception("Not Implemented");
 }
Ejemplo n.º 24
0
        public static async Task <Task> Action(ServerHandler shandler, HTTPRequest request, Stream body, IProxyHTTPEncoder encoder)
        {
            var buf = new byte[4096];
            int ndx = 0;
            int cnt;

            while ((cnt = await body.ReadAsync(buf, ndx, buf.Length - ndx)) > 0)
            {
                ndx += cnt;
            }

            var buf_utf8 = Encoding.UTF8.GetString(buf, 0, ndx);

            //Logger.WriteDebugString($"buf_utf8={buf_utf8}");

            var req = JsonConvert.DeserializeObject <DeviceConfigRequest>(buf_utf8);

            var path = Path.Combine(shandler.config_path, $"config_{req.deviceid}.data");

            if (!File.Exists(path))
            {
                var _fp = File.OpenWrite(
                    path
                    );

                var _tmp = new JObject();

                _tmp["userid"]      = null;
                _tmp["config_data"] = req.current_config_data;

                var _config_bytes_utf8 = Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(_tmp));
                await _fp.WriteAsync(_config_bytes_utf8, 0, _config_bytes_utf8.Length);

                _fp.Dispose();
            }

            //Logger.WriteDebugString($"The config path is {path}.");

            var fp = File.OpenRead(
                path
                );

            var config_bytes_utf8 = new byte[fp.Length];

            await fp.ReadAsync(config_bytes_utf8, 0, config_bytes_utf8.Length);

            fp.Dispose();

            var config_data = Encoding.UTF8.GetString(config_bytes_utf8);

            JObject tmp = JsonConvert.DeserializeObject <JObject>(config_data);

            tmp["config_data"] = JsonConvert.SerializeObject(
                JsonConvert.DeserializeObject <JObject>(tmp["config_data"].Value <string>()),
                Formatting.Indented
                );

            tmp["config_data"] = tmp["config_data"].Value <string>().Replace("\n", "\r\n");

            var resp = new DeviceConfigResponse();

            resp.success     = true;
            resp.config_data = JsonConvert.SerializeObject(tmp);

            Debug.WriteLine($"@@@@@ {resp.config_data}");

            await encoder.WriteQuickHeader(200, "OK");

            await encoder.BodyWriteSingleChunk(JsonConvert.SerializeObject(resp));

            return(Task.CompletedTask);
        }
        public static async Task <Task> Action(ServerHandler shandler, HTTPRequest request, Stream body, IProxyHTTPEncoder encoder)
        {
            var auth = await Helpers.ReadMessageFromStreamAndAuthenticate(shandler, 1024 * 16, body);

            if (!auth.success)
            {
                await encoder.WriteQuickHeader(403, "Must be authenticated.");

                await encoder.BodyWriteSingleChunk(JsonConvert.SerializeObject(new CommitConfigurationResponse()
                {
                    success = false,
                }));

                return(Task.CompletedTask);
            }

            if (!auth.user.admin)
            {
                await encoder.WriteQuickHeader(403, "Must be admin.");

                await encoder.BodyWriteSingleChunk(JsonConvert.SerializeObject(new CommitConfigurationResponse()
                {
                    success = false,
                }));

                return(Task.CompletedTask);
            }

            var req = JsonConvert.DeserializeObject <CommitConfigurationRequest>(auth.payload);

            var fp = File.OpenWrite(
                Path.Combine(shandler.config_path, $"config_{req.deviceid}.data")
                );

            var file_data = new ConfigFileData()
            {
                userid      = req.userid,
                config_data = req.config_data,
            };

            // TODO: *think* reliable operation and atomic as possible
            var config_bytes_utf8 = Encoding.UTF8.GetBytes(
                JsonConvert.SerializeObject(file_data)
                );
            await fp.WriteAsync(config_bytes_utf8, 0, config_bytes_utf8.Length);

            fp.Dispose();

            await encoder.WriteQuickHeader(200, "OK");

            await encoder.BodyWriteSingleChunk(JsonConvert.SerializeObject(new CommitConfigurationResponse()
            {
                success = true,
            }));

            return(Task.CompletedTask);
        }
Ejemplo n.º 26
0
        /// <summary>
        /// Handles reading header and data for data upload. A critical routine that employs as many checks as needed
        /// to ensure that written data is verified as written and correct.
        /// </summary>
        /// <param name="shandler"></param>
        /// <param name="request"></param>
        /// <param name="body"></param>
        /// <param name="encoder"></param>
        /// <returns></returns>
        public static async Task <Task> Action(ServerHandler shandler, HTTPRequest request, Stream body, IProxyHTTPEncoder encoder)
        {
            var buf    = new byte[1024 * 32];
            int bufndx = 0;
            int cnt;
            int tndx;

            do
            {
                cnt = await body.ReadAsync(buf, bufndx, buf.Length - bufndx);

                if (cnt > 0)
                {
                    bufndx += cnt;
                }

                tndx = Array.IndexOf(buf, (byte)'\n');

                if (bufndx >= buf.Length && tndx < 0)
                {
                    throw new ProgramException("On receiving upload header. The header size exceeded 4096-bytes.");
                }
            } while (cnt > 0 && tndx < 0);

            var hdrstr = Encoding.UTF8.GetString(buf, 0, tndx).Trim();

            Debug.WriteLine(hdrstr);

            var auth_package = JsonConvert.DeserializeObject <MDACS.API.Auth.Msg>(hdrstr);

            var payload = auth_package.payload;


            /*var info = await MDACS.API.Auth.AuthenticateMessageAsync(shandler.auth_url, auth_package);
             *
             * if (!info.success)
             * {
             *  throw new UnauthorizedException();
             * }
             */

            var hdr = JsonConvert.DeserializeObject <MDACS.API.Requests.UploadHeader>(payload);

            Array.Copy(buf, tndx + 1, buf, 0, bufndx - (tndx + 1));
            // Quasi-repurpose the variable `bufndx` to mark end of the slack data.
            bufndx = bufndx - (tndx + 1);

            var data_node = String.Format("{0}_{1}_{2}_{3}.{4}",
                                          hdr.datestr,
                                          hdr.userstr,
                                          hdr.devicestr,
                                          hdr.timestr,
                                          hdr.datatype
                                          );

            var data_node_path = Path.Combine(shandler.data_path, data_node);

            // Make the name unique and keep pertinent information in the event something fails.
            var temp_data_node_path = Path.Combine(
                shandler.data_path,
                $"temp_{DateTime.Now.ToFileTime().ToString()}_{data_node}"
                );

            // TODO: hash data then rehash data after writing to storage, maybe?

            SHA512 hasher;

            var fhash_sha512 = new byte[512 / 8];

            FileStream fp = null;

            try
            {
#if DEBUG
                //Logger.WriteDebugString($"Opening {temp_data_node_path} as temporary output for upload.");
#endif
                fp = File.Open(temp_data_node_path, FileMode.Create);
                await fp.WriteAsync(buf, 0, bufndx);

                long total = 0;

                hasher = SHA512Managed.Create();

                hasher.Initialize();

                while (true)
                {
                    var _cnt = await body.ReadAsync(buf, 0, buf.Length);

                    if (_cnt < 1)
                    {
                        break;
                    }

                    Debug.WriteLine($"buf={buf} _cnt={_cnt}");

                    // https://stackoverflow.com/questions/20634827/how-to-compute-hash-of-a-large-file-chunk
                    hasher.TransformBlock(buf, 0, _cnt, null, 0);

                    total += _cnt;
                    await fp.WriteAsync(buf, 0, _cnt);
                }

                hasher.TransformFinalBlock(buf, 0, 0);

                fhash_sha512 = hasher.Hash;

#if DEBUG
                //Logger.WriteDebugString($"Wrote {total} bytes to {temp_data_node_path} as temporary output for upload.");
#endif

                await body.CopyToAsync(fp);

                await fp.FlushAsync();

                fp.Dispose();
            }
            catch (Exception ex)
            {
                if (fp != null)
                {
                    fp.Dispose();
                }

#if DEBUG
                //Logger.WriteDebugString($"Exception on {temp_data_node_path} with:\n{ex}");
#endif

                File.Delete(temp_data_node_path);

                await encoder.WriteQuickHeader(500, "Problem");

                await encoder.BodyWriteSingleChunk("Problem during write to file from body stream.");

                return(Task.CompletedTask);
            }

#if DEBUG
            //Logger.WriteDebugString($"Upload for {temp_data_node_path} is done.");
#endif

            if (!await WaitForFileSizeMatch(temp_data_node_path, (long)hdr.datasize, 3))
            {
                File.Delete(temp_data_node_path);

                await encoder.WriteQuickHeader(504, "Timeout");

                await encoder.BodyWriteSingleChunk("The upload byte length of the destination never reached the intended stream size.");

                return(Task.CompletedTask);
            }

            try
            {
                if (File.Exists(data_node_path))
                {
                    await CheckedFileMoveAsync(data_node_path, $"{data_node_path}.moved.{DateTime.Now.ToFileTime().ToString()}");
                }

                await CheckedFileMoveAsync(temp_data_node_path, data_node_path);
            }
            catch (Exception)
            {
                // Delete the temporary since we should have saved the original.
                File.Delete(temp_data_node_path);
                // Move the original back to the original filename.
                await CheckedFileMoveAsync($"{data_node_path}.moved.{DateTime.Now.ToFileTime().ToString()}", data_node_path);

                await encoder.WriteQuickHeader(500, "Problem");

                await encoder.BodyWriteSingleChunk("Unable to do a CheckFileMoveAsync.");

                return(Task.CompletedTask);
            }

            if (!await WaitForFileSizeMatch(data_node_path, (long)hdr.datasize, 3))
            {
                await encoder.WriteQuickHeader(504, "Timeout");

                await encoder.BodyWriteSingleChunk("Timeout waiting for size change.");

                return(Task.CompletedTask);
            }

            Item item = new Item();

            hasher = new SHA512Managed();

            var security_id_bytes = hasher.ComputeHash(Encoding.UTF8.GetBytes(data_node));

            item.datasize         = hdr.datasize;
            item.datatype         = hdr.datatype;
            item.datestr          = hdr.datestr;
            item.devicestr        = hdr.devicestr;
            item.duration         = -1.0;
            item.fqpath           = data_node_path;
            item.metatime         = DateTime.Now.ToFileTimeUtc();
            item.node             = data_node;
            item.note             = "";
            item.security_id      = BitConverter.ToString(security_id_bytes).Replace("-", "").ToLower();
            item.timestr          = hdr.timestr;
            item.userstr          = hdr.userstr;
            item.state            = "";
            item.manager_uuid     = shandler.manager_uuid;
            item.data_hash_sha512 = Convert.ToBase64String(fhash_sha512);

            item.duration = MDACS.Database.MediaTools.MP4Info.GetDuration(item.fqpath);

            await shandler.WriteItemToJournal(item);

            var uresponse = new MDACS.API.Responses.UploadResponse();

            uresponse.success     = true;
            uresponse.fqpath      = item.fqpath;
            uresponse.security_id = item.security_id;

            shandler.UsedSpaceAdd((long)hdr.datasize);

            await encoder.WriteQuickHeader(200, "OK");

            await encoder.BodyWriteSingleChunk(JsonConvert.SerializeObject(uresponse));

            // Allow current execution to continue while spinning off the
            // a handler for this successful upload.
            shandler.HouseworkAfterUploadSuccess(item);

            return(Task.CompletedTask);
        }
Ejemplo n.º 27
0
        /// <summary>
        ///
        /// </summary>
        /// <param name="request"></param>
        /// <param name="body"></param>
        /// <param name="encoder"></param>
        /// <exception cref="UnauthorizedException">User has insufficient priviledges to modify the item.</exception>
        /// <exception cref="AuthenticationException">User is not valid for access of any type.</exception>
        /// <exception cref="InvalidArgumentException">One of the arguments was not correct or the reason for failure.</exception>
        /// <exception cref="ProgramException">Anything properly handled but needs handling for acknowlegement purposes.</exception>
        /// <exception cref="Exception">Anything else could result in instability.</exception>
        public static async Task <Task> Action(ServerHandler shandler, HTTPRequest request, Stream body, IProxyHTTPEncoder encoder)
        {
            var auth_resp = await Helpers.ReadMessageFromStreamAndAuthenticate(shandler, 1024 * 16, body);

            if (!auth_resp.success)
            {
                throw new UnauthorizedException();
            }

            var sreq = JsonConvert.DeserializeObject <API.Requests.CommitSetRequest>(auth_resp.payload);

            Monitor.Enter(shandler.items);

            Item item;

#if DEBUG
            //Logger.WriteDebugString($"sreq.security_id={sreq.security_id}");
#endif

            try
            {
                if (!shandler.items.ContainsKey(sreq.security_id))
                {
                    await encoder.WriteQuickHeader(404, "Not Found");

                    await encoder.BodyWriteSingleChunk("");

                    return(Task.CompletedTask);
                }

                item = shandler.items[sreq.security_id];
            }
            catch (Exception ex)
            {
#if DEBUG
                //Logger.WriteDebugString($"Exception on getting item was:\n{ex}");
#endif
                await encoder.WriteQuickHeader(500, "Error");

                await encoder.BodyWriteSingleChunk("");

                return(Task.CompletedTask);
            }
            finally
            {
                Monitor.Exit(shandler.items);
            }

            if (!Helpers.CanUserModifyItem(auth_resp.user, item))
            {
#if DEBUG
                //Logger.WriteDebugString($"User was not authorized to write to item.");
#endif
                await encoder.WriteQuickHeader(403, "Not Authorized");

                await encoder.BodyWriteSingleChunk("");

                return(Task.CompletedTask);
            }

            // Check fields to see if the user is authorized to modify them.
            foreach (var pair in sreq.meta)
            {
                if (!await shandler.FieldModificationValidForUser(auth_resp.user, pair.Key))
                {
                    await encoder.WriteQuickHeader(403, "Not Authorized");

                    await encoder.BodyWriteSingleChunk("");

                    return(Task.CompletedTask);
                }
            }

            try
            {
                foreach (var pair in sreq.meta)
                {
                    // Reflection simplified coding time at the expense of performance.
                    var field = item.GetType().GetField(pair.Key);
                    field.SetValue(item, pair.Value.ToObject(field.FieldType));

#if DEBUG
                    //Logger.WriteDebugString($"Set field {field} of {sreq.meta} to {pair.Value.ToString()}.");
#endif
                }

                shandler.items[sreq.security_id] = item;

                if (!await shandler.WriteItemToJournal(item))
                {
#if DEBUG
                    //Logger.WriteDebugString($"Error happened when writing to the journal for a commit set operation.");
#endif
                    await encoder.WriteQuickHeader(500, "Error");

                    await encoder.BodyWriteSingleChunk("");

                    return(Task.CompletedTask);
                }
            }
            catch (Exception)
            {
#if DEBUG
                //Logger.WriteDebugString($"Error happened when writing to journal or setting item fields during commit set operation.");
#endif
                await encoder.WriteQuickHeader(500, "Error");

                await encoder.BodyWriteSingleChunk("");

                return(Task.CompletedTask);
            }

            var resp = new MDACS.API.Responses.CommitSetResponse();

            resp.success = true;

            await encoder.WriteQuickHeader(200, "OK");

            await encoder.BodyWriteSingleChunk(JsonConvert.SerializeObject(resp));

            return(Task.CompletedTask);
        }
        public static async Task <Task> Action(ServerHandler shandler, HTTPRequest request, Stream body, IProxyHTTPEncoder encoder)
        {
            var auth = await Helpers.ReadMessageFromStreamAndAuthenticate(shandler, 1024 * 16, body);

            if (!auth.success)
            {
                return(encoder.Response(403, "Denied").SendNothing());
            }

            var resp = new EnumerateConfigurationsResponse();

            resp.success = true;

            resp.configs = new Dictionary <string, string>();

            try
            {
                foreach (var node in Directory.EnumerateFiles(shandler.config_path))
                {
                    var fnode = Path.Combine(shandler.data_path, node);

                    var fnode_filename = Path.GetFileName(fnode);

                    if (fnode_filename.StartsWith("config_") && fnode_filename.EndsWith(".data"))
                    {
                        var fd = File.OpenRead(fnode);

                        var buf = new byte[fd.Length];

                        int cnt = 0;

                        while (cnt < buf.Length)
                        {
                            cnt += await fd.ReadAsync(buf, cnt, buf.Length - cnt);
                        }

                        var buf_text = Encoding.UTF8.GetString(buf);

                        var id = fnode_filename.Substring(fnode_filename.IndexOf("_") + 1);

                        id = id.Substring(0, id.LastIndexOf("."));

                        resp.configs[id] = buf_text;

                        fd.Dispose();
                    }
                }
            }
            catch (Exception ex)
            {
                //Logger.WriteCriticalString($"Error during configuration enumeration as follows:\n{ex}");

                return(encoder.Response(500, "Error").SendNothing());
            }

            return(encoder.Response(200, "OK").SendJsonFromObject(resp));
        }
Ejemplo n.º 29
0
        public static async Task <Task> Action(ServerHandler shandler, HTTPRequest request, Stream body, IProxyHTTPEncoder encoder)
        {
            var auth_resp = await Helpers.ReadMessageFromStreamAndAuthenticate(shandler, 1024 * 16, body);

            if (!auth_resp.success)
            {
                return(encoder.Response(403, "Denied").SendNothing());
            }

            var reply = new HandleDataReply();

            reply.data = new Item[shandler.items.Count];

            lock (shandler.items)
            {
                int x = 0;

                foreach (var pair in shandler.items)
                {
                    if (
                        Helpers.CanUserSeeItem(auth_resp.user, pair.Value)
                        )
                    {
                        reply.data[x++] = pair.Value;
                    }
                }
            }

            return(encoder.Response(200, "OK").SendJsonFromObject(reply));
        }
Ejemplo n.º 30
0
        static public async Task <Task> Action(ServerHandler shandler, HTTPRequest request, Stream body, IProxyHTTPEncoder encoder)
        {
            // This URL route was never implemented with user security. The security ID itself is the security, but that
            // could be revised.
            //var auth = await ReadMessageFromStreamAndAuthenticate(1024 * 16, body);
            //if (!auth.success)
            //{
            //    throw new UnauthorizedException();
            //}

            String download_sid;

            if (request.query_string.Length > 0)
            {
                download_sid = request.query_string;
            }
            else
            {
                //req = JsonConvert.DeserializeObject<HandleDownloadRequest>(auth.payload);
                //download_sid = req.security_id;
                throw new InvalidArgumentException();
            }

            Item item;

            lock (shandler.items)
            {
                if (!shandler.items.ContainsKey(download_sid))
                {
                    throw new InvalidArgumentException();
                }

                item = shandler.items[download_sid];
            }

            var item_data_path = Path.Combine(shandler.data_path, item.node);

            var fd = File.OpenRead(item_data_path);

            ulong offset_start = 0;
            // How can a stream be negative? Could this stream ever be negative? What purpose does it suit?
            ulong offset_size = (ulong)fd.Length;
            ulong total_size  = (ulong)fd.Length;

            String response_code = "200";

            if (request.internal_headers.ContainsKey("range"))
            {
                var range_str = request.internal_headers["range"];

                var eqndx = range_str.IndexOf("=");

                if (eqndx > -1)
                {
                    var range_sub_str   = range_str.Substring(eqndx + 1).Trim();
                    var range_nums_strs = range_sub_str.Split("-");

                    if (range_nums_strs.Length > 1)
                    {
                        offset_start = ulong.Parse(range_nums_strs[0]);

                        if (range_nums_strs[1].Equals(""))
                        {
                            offset_size = (ulong)fd.Length - offset_start;
                        }
                        else
                        {
                            offset_size = ulong.Parse(range_nums_strs[1]) - offset_start + 1;
                        }
                        response_code = "206";
                    }
                }
            }

            checked
            {
                fd.Seek((long)offset_start, SeekOrigin.Begin);
            }

            fd.Seek((long)offset_start, SeekOrigin.Begin);

            String mime_type = null;

            switch (item.datatype)
            {
            case "mp4":
                mime_type = "video/mp4";
                break;

            case "jpg":
                mime_type = "image/jpeg";
                break;
            }

            using (var de_stream = new LimitedStream(fd, offset_size))
            {
                var header = new Dictionary <String, String>();

                header.Add("$response_code", response_code);
                header.Add("$response_text", "Partial Content");
                header.Add("content-disposition",
                           String.Format("inline; filename=\"{0}_{1}_{2}_{3}.{4}\"",
                                         item.datestr,
                                         item.userstr,
                                         item.devicestr,
                                         item.timestr,
                                         item.datatype
                                         )
                           );
                header.Add("accept-ranges", "bytes");
                header.Add("content-range",
                           String.Format("bytes {0}-{1}/{2}",
                                         offset_start,
                                         offset_size + offset_start - 1,
                                         total_size
                                         )
                           );

                if (mime_type != null)
                {
                    header.Add("content-type", mime_type);
                }

                await encoder.WriteHeader(header);

                await encoder.BodyWriteStream(de_stream);

                return(Task.CompletedTask);
            }
        }