HttpAccess.h
| Line | Branch | Exec | Source |
|---|---|---|---|
| 1 | #ifndef httpaccess_h | ||
| 2 | #define httpaccess_h | ||
| 3 | #include <string.h> | ||
| 4 | #include <strings.h> | ||
| 5 | |||
| 6 | // Who may reach what on port 80 under Secured | ||
| 7 | // (docs/adr/0006-two-security-modes-eleven-http-routes.md). Paths are the | ||
| 8 | // request's path, without the query. | ||
| 9 | |||
| 10 | // The files the web UI loads, which all sit in the root. Static serving | ||
| 11 | // answers these alone, so the rolling codes in shades.cfg leave the device | ||
| 12 | // only through /backup. A path below a route, such as /backup/a.js, isn't one. | ||
| 13 | 41 | inline bool isWebAsset(const char *path) { | |
| 14 | 41 | if(!path || path[0] != '/' || strchr(path + 1, '/') || strstr(path, "..")) return false; | |
| 15 | 26 | if(strcmp(path, "/") == 0 || strcmp(path, "/appversion") == 0) return true; | |
| 16 | static const char *const types[] = {".html", ".js", ".css", ".png", ".svg", ".ico"}; | ||
| 17 | 23 | const size_t len = strlen(path); | |
| 18 | 133 | for(const char *type : types) { | |
| 19 | 117 | const size_t n = strlen(type); | |
| 20 | 117 | if(len > n + 1 && strcmp(path + len - n, type) == 0) return true; | |
| 21 | } | ||
| 22 | 16 | return false; | |
| 23 | } | ||
| 24 | |||
| 25 | // True for what anyone may reach without a token: the web UI's files, what | ||
| 26 | // logging in needs, SSDP's description and preflight requests. /ws is here | ||
| 27 | // because the socket checks its own token in the handshake, from the query. | ||
| 28 | 25 | inline bool isPublicRoute(const char *path, bool preflight) { | |
| 29 | 25 | if(preflight) return true; | |
| 30 | 24 | if(!path) return false; | |
| 31 | static const char *const routes[] = {"/loginContext", "/login", "/upnp.xml", "/ws"}; | ||
| 32 | 105 | for(const char *route : routes) | |
| 33 | 86 | if(strcmp(path, route) == 0) return true; | |
| 34 | 19 | return isWebAsset(path); | |
| 35 | } | ||
| 36 | |||
| 37 | // True when a socket handshake comes from a page the device served. A | ||
| 38 | // browser always sends Origin with a handshake, so another site's page open | ||
| 39 | // on the LAN can't use a token the browser holds. Clients that aren't | ||
| 40 | // browsers send none. | ||
| 41 | 16 | inline bool originMatchesHost(const char *origin, const char *host) { | |
| 42 | 16 | if(!origin) return true; | |
| 43 | static const char *const schemes[] = {"http://", "https://"}; | ||
| 44 | 20 | for(const char *scheme : schemes) { | |
| 45 | 18 | const size_t n = strlen(scheme); | |
| 46 | 18 | if(strncasecmp(origin, scheme, n) == 0) return host && host[0] && strcasecmp(origin + n, host) == 0; | |
| 47 | } | ||
| 48 | 2 | return false; | |
| 49 | } | ||
| 50 | #endif | ||
| 51 |