source: binary-improvements/MapRendering/Web/Web.cs @ 247

Last change on this file since 247 was 247, checked in by alloc, 4 years ago

Fixes

File size: 7.8 KB
Line 
1using System;
2using System.Collections.Generic;
3using System.Collections.Specialized;
4using System.IO;
5using System.Net;
6using System.Net.Sockets;
7using System.Reflection;
8using System.Text;
9using System.Threading;
10using UnityEngine;
11
12using AllocsFixes.NetConnections.Servers.Web.Handlers;
13
14namespace AllocsFixes.NetConnections.Servers.Web
15{
16        public class Web : IConsoleServer {
17                private const int GUEST_PERMISSION_LEVEL = 2000;
18                private readonly HttpListener _listener = new HttpListener ();
19                private Dictionary<string, PathHandler> handlers = new Dictionary<string, PathHandler> ();
20                public static int handlingCount = 0;
21                public static int currentHandlers = 0;
22                private string dataFolder;
23                private bool useStaticCache = false;
24
25                public bool isSslRedirected {
26                        private set;
27                        get;
28                }
29
30                public ConnectionHandler connectionHandler;
31
32                public Web () {
33                        try {
34                                int webPort = GamePrefs.GetInt (EnumGamePrefs.ControlPanelPort);
35                                if (webPort < 1 || webPort > 65533) {
36                                        Log.Out ("Webserver not started (ControlPanelPort not within 1-65533)");
37                                        return;
38                                }
39                                if (!Directory.Exists (Path.GetDirectoryName (Assembly.GetExecutingAssembly ().Location) + "/webserver")) {
40                                        Log.Out ("Webserver not started (folder \"webserver\" not found in WebInterface mod folder)");
41                                        return;
42                                }
43
44                                // TODO: Read from config
45                                isSslRedirected = false;
46                                useStaticCache = false;
47
48                                dataFolder = Path.GetDirectoryName (Assembly.GetExecutingAssembly ().Location) + "/webserver";
49
50                                if (!HttpListener.IsSupported) {
51                                        Log.Out ("Webserver not started (needs Windows XP SP2, Server 2003 or later or Mono)");
52                                        return;
53                                }
54 
55                                handlers.Add (
56                                                "/index.htm",
57                                                new SimpleRedirectHandler ("/static/index.html"));
58                                handlers.Add (
59                                                "/favicon.ico",
60                                                new SimpleRedirectHandler ("/static/favicon.ico"));
61                                handlers.Add (
62                                                "/session/",
63                                                new SessionHandler (
64                                                                        "/session/",
65                                                                        dataFolder,
66                                                                        this)
67                                );
68                                handlers.Add (
69                                                "/userstatus",
70                                                new UserStatusHandler ()
71                                );
72                                if (useStaticCache) {
73                                        handlers.Add (
74                                                        "/static/",
75                                                        new StaticHandler (
76                                                                        "/static/",
77                                                                        dataFolder,
78                                                                        new AllocsFixes.FileCache.SimpleCache (),
79                                                                        true)
80                                        );
81                                } else {
82                                        handlers.Add (
83                                                        "/static/",
84                                                        new StaticHandler (
85                                                                        "/static/",
86                                                                        dataFolder,
87                                                                        new AllocsFixes.FileCache.DirectAccess (),
88                                                                        true)
89                                        );
90                                }
91
92                                handlers.Add (
93                                        "/itemicons/",
94                                        new ItemIconHandler (
95                                                "/itemicons/",
96                                                true)
97                                );
98
99                                handlers.Add (
100                                        "/map/",
101                                        new StaticHandler (
102                                                "/map/",
103                                                GameUtils.GetSaveGameDir () + "/map",
104                                                MapRendering.MapRendering.GetTileCache (),
105                                                false,
106                                                "web.map")
107                                );
108
109                                handlers.Add (
110                                        "/api/",
111                                        new ApiHandler ("/api/")
112                                );
113
114                                connectionHandler = new ConnectionHandler (this);
115
116                                _listener.Prefixes.Add (String.Format ("http://*:{0}/", webPort + 2));
117                                _listener.Start ();
118
119                                SdtdConsole.Instance.RegisterServer (this);
120
121                                _listener.BeginGetContext (new AsyncCallback (HandleRequest), _listener);
122
123                                Log.Out ("Started Webserver on " + (webPort + 2));
124                        } catch (Exception e) {
125                                Log.Out ("Error in Web.ctor: " + e);
126                        }
127                }
128
129                private void HandleRequest (IAsyncResult result) {
130                        if (_listener.IsListening) {
131                                Interlocked.Increment (ref handlingCount);
132                                Interlocked.Increment (ref currentHandlers);
133                                HttpListenerContext ctx = _listener.EndGetContext (result);
134                                _listener.BeginGetContext (new AsyncCallback (HandleRequest), _listener);
135                                try {
136                                        HttpListenerRequest request = ctx.Request;
137                                        HttpListenerResponse response = ctx.Response;
138
139                                        response.ProtocolVersion = new Version ("1.1");
140
141                                        WebConnection conn;
142                                        int permissionLevel = DoAuthentication (request, out conn);
143
144
145                                        //Log.Out ("Login status: conn!=null: {0}, permissionlevel: {1}", conn != null, permissionLevel);
146
147
148                                        if (conn != null) {
149                                                Cookie cookie = new Cookie ("sid", conn.SessionID, "/");
150                                                cookie.Expired = false;
151                                                cookie.Expires = new DateTime (2020, 1, 1);
152                                                cookie.HttpOnly = true;
153                                                cookie.Secure = false;
154                                                response.AppendCookie (cookie);
155                                        }
156
157                                        if (request.Url.AbsolutePath.Length < 2) {
158                                                handlers ["/index.htm"].HandleRequest (request, response, conn, permissionLevel);
159                                                return;
160                                        } else {
161                                                foreach (KeyValuePair<string, PathHandler> kvp in handlers) {
162                                                        if (request.Url.AbsolutePath.StartsWith (kvp.Key)) {
163                                                                if (!kvp.Value.IsAuthorizedForHandler (conn, permissionLevel)) {
164                                                                        response.StatusCode = (int)HttpStatusCode.Forbidden;
165                                                                        if (conn != null) {
166                                                                                //Log.Out ("Web.HandleRequest: user '{0}' not allowed to access '{1}'", conn.SteamID, kvp.Value.ModuleName);
167                                                                        } else {
168                                                                                //Log.Out ("Web.HandleRequest: unidentified user from '{0}' not allowed to access '{1}'", request.RemoteEndPoint.Address, kvp.Value.ModuleName);
169                                                                        }
170                                                                } else {
171                                                                        kvp.Value.HandleRequest (request, response, conn, permissionLevel);
172                                                                }
173                                                                return;
174                                                        }
175                                                }
176                                        }
177
178                                        Log.Out ("Error in Web.HandleRequest(): No handler found for path \"" + request.Url.AbsolutePath + "\"");
179                                        response.StatusCode = (int)HttpStatusCode.NotFound;
180                                } catch (IOException e) {
181                                        if (e.InnerException is SocketException) {
182                                                Log.Out ("Error in Web.HandleRequest(): Remote host closed connection: " + e.InnerException.Message);
183                                        } else {
184                                                Log.Out ("Error (IO) in Web.HandleRequest(): " + e);
185                                        }
186                                } catch (Exception e) {
187                                        Log.Out ("Error in Web.HandleRequest(): " + e);
188                                } finally {
189                                        if (ctx != null) {
190                                                ctx.Response.Close ();
191                                        }
192                                        Interlocked.Decrement (ref currentHandlers);
193                                }
194                        }
195                }
196
197                private int DoAuthentication (HttpListenerRequest _req, out WebConnection _con) {
198                        _con = null;
199
200                        string sessionId = null;
201                        if (_req.Cookies ["sid"] != null) {
202                                sessionId = _req.Cookies ["sid"].Value;
203                        }
204
205                        if (!string.IsNullOrEmpty (sessionId)) {
206                                WebConnection con = connectionHandler.IsLoggedIn (sessionId, _req.RemoteEndPoint.Address.ToString ());
207                                if (con != null) {
208                                        _con = con;
209                                        return GameManager.Instance.adminTools.GetAdminToolsClientInfo (_con.SteamID.ToString ()).PermissionLevel;
210                                }
211                        }
212
213                        if (_req.QueryString ["adminuser"] != null && _req.QueryString ["admintoken"] != null) {
214                                WebPermissions.AdminToken admin = WebPermissions.Instance.GetWebAdmin (_req.QueryString ["adminuser"], _req.QueryString ["admintoken"]);
215                                if (admin != null) {
216                                        return admin.permissionLevel;
217                                } else {
218                                        Log.Warning ("Invalid Admintoken used from " + _req.RemoteEndPoint.ToString ());
219                                }
220                        }
221
222                        if (_req.Url.AbsolutePath.StartsWith ("/session/verify")) {
223                                ulong id = OpenID.Validate (_req);
224                                if (id > 0) {
225                                        WebConnection con = connectionHandler.LogIn (id, _req.RemoteEndPoint.Address.ToString ());
226                                        _con = con;
227                                        //Log.Out ("Logged in with session id: {0}", con.SessionID);
228                                        return GameManager.Instance.adminTools.GetAdminToolsClientInfo (id.ToString ()).PermissionLevel;
229                                } else {
230                                        Log.Out ("Steam OpenID login failed from {0}", _req.RemoteEndPoint.ToString ());
231                                }
232                        }
233
234                        return GUEST_PERMISSION_LEVEL;
235                }
236
237                public void Disconnect () {
238                        try {
239                                _listener.Stop ();
240                                _listener.Close ();
241                        } catch (Exception e) {
242                                Log.Out ("Error in Web.Disconnect: " + e);
243                        }
244                }
245
246                public void SendLine (string line) {
247                        connectionHandler.SendLine (line);
248                }
249
250                public void SendLog (string text, string trace, UnityEngine.LogType type) {
251                        connectionHandler.SendLog (text, trace, type);
252                }
253
254                public static void SetResponseTextContent (HttpListenerResponse resp, string text) {
255                        byte[] buf = Encoding.UTF8.GetBytes (text);
256                        resp.ContentLength64 = buf.Length;
257                        resp.ContentType = "text/html";
258                        resp.ContentEncoding = Encoding.UTF8;
259                        resp.OutputStream.Write (buf, 0, buf.Length);
260                }
261
262        }
263}
Note: See TracBrowser for help on using the repository browser.