An app written in GoLang to find people using location services on smartphones.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

746 lines
23 KiB

  1. package main
  2. import (
  3. "net/http"
  4. "net/url"
  5. "html/template"
  6. "log"
  7. "encoding/json"
  8. "io/ioutil"
  9. "regexp"
  10. "github.com/go-redis/redis"
  11. "time"
  12. "strconv"
  13. "crypto/rand"
  14. "flag"
  15. "fmt"
  16. "os"
  17. "gopkg.in/ldap.v2"
  18. "strings"
  19. "encoding/base64"
  20. "encoding/pem"
  21. "crypto/x509"
  22. "crypto/rsa"
  23. "crypto"
  24. )
  25. type location_set struct {
  26. Latitude float64 `json:"latitude"`
  27. Longitude float64 `json:"longitude"`
  28. Id string `json:"id"`
  29. Key string `json:"key"`
  30. }
  31. type item_key struct {
  32. Id string
  33. Key string
  34. }
  35. type loginmethods struct {
  36. Ldap bool
  37. Azuread bool
  38. }
  39. type Config struct {
  40. Redis struct {
  41. Host string `json:"hostname"`
  42. Port int `json:"port"`
  43. Password string `json:"password"`
  44. Database int `json:"db"`
  45. } `json:"redis"`
  46. Ldap struct {
  47. Binddn string `json:"binddn"`
  48. Bindpassword string `json:"bindpassword"`
  49. Host string `json:"host"`
  50. Basedn string `json:"basesearchdn"`
  51. Port int `json:"port"`
  52. Searchobject string `json:"searchobject"`
  53. Enabled bool `json:"enabled"`
  54. } `json:"ldap"`
  55. Azuread struct {
  56. Tenantid string `json:"tenantid"`
  57. Clientid string `json:"clientid"`
  58. Redirecturi string `json:"redirecturi"`
  59. Enabled bool `json:"enabled"`
  60. } `json:"azuread"`
  61. Securecookies bool `json:"securecookies"`
  62. }
  63. type TokenHeader struct {
  64. Type string `json:"typ"`
  65. Algorithm string `json:"alg"`
  66. KeyID string `json:"kid"`
  67. }
  68. type TokenClaims struct {
  69. Audience string `json:"aud"`
  70. Issued int64 `json:"iat"`
  71. Expires int64 `json:"exp"`
  72. NotBefore int64 `json:"nbf"`
  73. Nonce string `json:"nonce"`
  74. }
  75. type OpenIDJWKS struct {
  76. Jwksuri string `json:"jwks_uri"`
  77. }
  78. type OpenIDKey struct {
  79. Keytype string `json:"kty"`
  80. Use string `json:"use"`
  81. KeyID string `json:"kid"`
  82. N string `json:"n"`
  83. E string `json:"e"`
  84. X5c []string `json:"x5c"`
  85. Issuer string `json:"issuer"`
  86. }
  87. type TenantKeys struct {
  88. Keys []OpenIDKey `json:"keys"`
  89. }
  90. var Configuration Config
  91. var Redis *redis.Client
  92. var Tenantkeys TenantKeys
  93. func setlocation(w http.ResponseWriter, r *http.Request){
  94. item := item_key{r.FormValue("id"), r.FormValue("key")}
  95. t, err := template.ParseFiles("setlocation.html")
  96. if err != nil {
  97. log.Print("template parsing error: ", err)
  98. }
  99. err = t.Execute(w, item)
  100. if err != nil {
  101. log.Print("template executing error: ", err)
  102. }
  103. }
  104. func getlocation(w http.ResponseWriter, r *http.Request){
  105. item := item_key{r.FormValue("id"), r.FormValue("key")}
  106. t, err := template.ParseFiles("getlocation.html")
  107. if err != nil {
  108. log.Print("template parsing error: ", err)
  109. }
  110. err = t.Execute(w, item)
  111. if err != nil {
  112. log.Print("template executing error: ", err)
  113. }
  114. }
  115. func managelocations(w http.ResponseWriter, r *http.Request){
  116. sessionid, err := r.Cookie("sessionid")
  117. if err != nil {
  118. http.Redirect(w, r, "/login.html", http.StatusSeeOther)
  119. return
  120. }
  121. if check_sessionid(sessionid.Value) != true {
  122. http.Redirect(w, r, "/login.html", http.StatusSeeOther)
  123. return
  124. }
  125. t, err := template.ParseFiles("managelocations.html")
  126. if err != nil {
  127. log.Print("template parsing error: ", err)
  128. }
  129. err = t.Execute(w, nil)
  130. if err != nil {
  131. log.Print("template executing error: ", err)
  132. }
  133. }
  134. func api_location(w http.ResponseWriter, r *http.Request){
  135. switch r.Method {
  136. case "GET":
  137. id := r.FormValue("id")
  138. key := r.FormValue("key")
  139. id_exists := check_item_key(id, key)
  140. if id_exists != true {
  141. w.WriteHeader(http.StatusNotFound)
  142. w.Write([]byte(http.StatusText(http.StatusNotFound) + "\n"))
  143. return
  144. }
  145. latitude, latitude_err := read_key("latitude-" + id)
  146. if latitude_err != true {
  147. w.WriteHeader(http.StatusNoContent)
  148. w.Write([]byte(http.StatusText(http.StatusNoContent) + "\n"))
  149. return
  150. }
  151. longitude, longitude_err := read_key("longitude-" + id)
  152. if longitude_err != true {
  153. w.WriteHeader(http.StatusNoContent)
  154. w.Write([]byte(http.StatusText(http.StatusNoContent) + "\n"))
  155. return
  156. }
  157. output, marshal_err := json.Marshal(map[string]float64{"latitude": latitude, "longitude": longitude})
  158. if marshal_err != nil {
  159. w.WriteHeader(http.StatusInternalServerError)
  160. w.Write([]byte(http.StatusText(http.StatusInternalServerError) + "\n"))
  161. return
  162. }
  163. w.Write([]byte(output))
  164. return
  165. case "POST":
  166. body, err := ioutil.ReadAll(r.Body)
  167. if err != nil {
  168. w.WriteHeader(http.StatusBadRequest)
  169. w.Write([]byte(http.StatusText(http.StatusBadRequest) + "\n"))
  170. return
  171. }
  172. var location_data location_set
  173. location_err := json.Unmarshal(body, &location_data)
  174. if location_err != nil {
  175. w.WriteHeader(http.StatusBadRequest)
  176. w.Write([]byte(http.StatusText(http.StatusBadRequest) + "\n"))
  177. return
  178. }
  179. id_exists := check_item_key(location_data.Id, location_data.Key)
  180. if id_exists != true {
  181. w.WriteHeader(http.StatusNotFound)
  182. w.Write([]byte(http.StatusText(http.StatusNotFound) + "\n"))
  183. return
  184. }
  185. latitude_written := write_key("latitude-" + location_data.Id, location_data.Latitude)
  186. if latitude_written != true {
  187. w.WriteHeader(http.StatusInternalServerError)
  188. w.Write([]byte(http.StatusText(http.StatusInternalServerError) + "\n"))
  189. return
  190. }
  191. longitude_written := write_key("longitude-" + location_data.Id, location_data.Longitude)
  192. if longitude_written != true {
  193. w.WriteHeader(http.StatusInternalServerError)
  194. w.Write([]byte(http.StatusText(http.StatusInternalServerError) + "\n"))
  195. return
  196. }
  197. w.WriteHeader(http.StatusCreated)
  198. w.Write([]byte(http.StatusText(http.StatusCreated) + "\n"))
  199. return
  200. default:
  201. w.WriteHeader(http.StatusNotImplemented)
  202. w.Write([]byte(http.StatusText(http.StatusNotImplemented) + "\n"))
  203. }
  204. }
  205. func api_createid(w http.ResponseWriter, r *http.Request){
  206. switch r.Method {
  207. case "GET":
  208. sessionid, err := r.Cookie("sessionid")
  209. if err != nil {
  210. http.Redirect(w, r, "/login.html", http.StatusSeeOther)
  211. return
  212. }
  213. if check_sessionid(sessionid.Value) != true {
  214. http.Redirect(w, r, "/login.html", http.StatusSeeOther)
  215. return
  216. }
  217. id, id_err := genrandomstring(10)
  218. if id_err != nil {
  219. w.WriteHeader(http.StatusInternalServerError)
  220. w.Write([]byte(http.StatusText(http.StatusInternalServerError) + "\n"))
  221. return
  222. }
  223. key, key_err := genrandomstring(32)
  224. if key_err != nil {
  225. w.WriteHeader(http.StatusInternalServerError)
  226. w.Write([]byte(http.StatusText(http.StatusInternalServerError) + "\n"))
  227. return
  228. }
  229. _, err = Redis.Get("key-" + id).Result()
  230. if err == nil {
  231. w.WriteHeader(http.StatusInternalServerError)
  232. w.Write([]byte(http.StatusText(http.StatusInternalServerError) + "\n"))
  233. return
  234. }
  235. writekey_err := Redis.Set("key-" + id, key, 30 * time.Minute).Err()
  236. if writekey_err != nil {
  237. w.WriteHeader(http.StatusInternalServerError)
  238. w.Write([]byte(http.StatusText(http.StatusInternalServerError) + "\n"))
  239. return
  240. }
  241. output, marshal_err := json.Marshal(map[string]string{"id": id, "key": key})
  242. if marshal_err != nil {
  243. w.WriteHeader(http.StatusInternalServerError)
  244. w.Write([]byte(http.StatusText(http.StatusInternalServerError) + "\n"))
  245. return
  246. }
  247. w.WriteHeader(http.StatusOK)
  248. w.Write([]byte(output))
  249. return
  250. default:
  251. w.WriteHeader(http.StatusNotImplemented)
  252. w.Write([]byte(http.StatusText(http.StatusNotImplemented) + "\n"))
  253. }
  254. }
  255. func login(w http.ResponseWriter, r *http.Request){
  256. loginmethods := loginmethods{Configuration.Ldap.Enabled, Configuration.Azuread.Enabled}
  257. switch r.Method {
  258. case "GET":
  259. sessionid, err := r.Cookie("sessionid")
  260. if err != nil {
  261. t, err := template.ParseFiles("login.html")
  262. if err != nil {
  263. log.Print("template parsing error: ", err)
  264. }
  265. err = t.Execute(w, loginmethods)
  266. if err != nil {
  267. log.Print("template executing error: ", err)
  268. }
  269. return
  270. }
  271. if check_sessionid(sessionid.Value) != true {
  272. t, err := template.ParseFiles("login.html")
  273. if err != nil {
  274. log.Print("template parsing error: ", err)
  275. }
  276. err = t.Execute(w, loginmethods)
  277. if err != nil {
  278. log.Print("template executing error: ", err)
  279. }
  280. return
  281. }
  282. http.Redirect(w, r, "/", http.StatusSeeOther)
  283. return
  284. case "POST":
  285. if Configuration.Ldap.Enabled {
  286. r.ParseForm()
  287. username := r.FormValue("username")
  288. password := r.FormValue("password")
  289. if authenticate(username, password) != true {
  290. http.Redirect(w, r, "/login.html", http.StatusSeeOther)
  291. return
  292. }
  293. sessionid, err := genrandomstring(32)
  294. if err != nil {
  295. w.WriteHeader(http.StatusInternalServerError)
  296. w.Write([]byte(http.StatusText(http.StatusInternalServerError) + "\n"))
  297. return
  298. }
  299. err = Redis.Set("session-" + sessionid, username, 30 * time.Minute).Err()
  300. if err != nil {
  301. w.WriteHeader(http.StatusInternalServerError)
  302. w.Write([]byte(http.StatusText(http.StatusInternalServerError) + "\n"))
  303. return
  304. }
  305. var sessioncookie http.Cookie
  306. if Configuration.Securecookies {
  307. sessioncookie = http.Cookie{
  308. Name: "sessionid",
  309. Value: sessionid,
  310. Path: "/",
  311. SameSite: http.SameSiteStrictMode,
  312. Secure: true,
  313. }
  314. } else {
  315. sessioncookie = http.Cookie{
  316. Name: "sessionid",
  317. Value: sessionid,
  318. Path: "/",
  319. SameSite: http.SameSiteStrictMode,
  320. }
  321. }
  322. http.SetCookie(w, &sessioncookie)
  323. http.Redirect(w, r, "/managelocations.html", http.StatusSeeOther)
  324. return
  325. }
  326. w.WriteHeader(http.StatusNotImplemented)
  327. w.Write([]byte(http.StatusText(http.StatusNotImplemented) + "\n"))
  328. return
  329. default:
  330. w.WriteHeader(http.StatusNotImplemented)
  331. w.Write([]byte(http.StatusText(http.StatusNotImplemented) + "\n"))
  332. }
  333. }
  334. func azureadlogin(w http.ResponseWriter, r *http.Request){
  335. switch r.Method {
  336. case "GET":
  337. sessionid, err := r.Cookie("sessionid")
  338. if err != nil {
  339. url, err := azureredirect()
  340. if err != nil {
  341. w.WriteHeader(http.StatusInternalServerError)
  342. w.Write([]byte(http.StatusText(http.StatusInternalServerError) + "\n"))
  343. return
  344. }
  345. http.Redirect(w, r, url, http.StatusSeeOther)
  346. return
  347. }
  348. if check_sessionid(sessionid.Value) != true {
  349. url, err := azureredirect()
  350. if err != nil {
  351. w.WriteHeader(http.StatusInternalServerError)
  352. w.Write([]byte(http.StatusText(http.StatusInternalServerError) + "\n"))
  353. return
  354. }
  355. http.Redirect(w, r, url, http.StatusSeeOther)
  356. return
  357. }
  358. http.Redirect(w, r, "/", http.StatusSeeOther)
  359. return
  360. case "POST":
  361. r.ParseForm()
  362. id_token := r.FormValue("id_token")
  363. state := r.FormValue("state")
  364. // validate token here
  365. valid_token := validate_id_token(id_token, state)
  366. if valid_token != true {
  367. http.Redirect(w, r, "/login.html", http.StatusSeeOther)
  368. return
  369. }
  370. sessionid, err := genrandomstring(32)
  371. if err != nil {
  372. w.WriteHeader(http.StatusInternalServerError)
  373. w.Write([]byte(http.StatusText(http.StatusInternalServerError) + "\n"))
  374. return
  375. }
  376. err = Redis.Set("session-" + sessionid, id_token, 30 * time.Minute).Err()
  377. if err != nil {
  378. w.WriteHeader(http.StatusInternalServerError)
  379. w.Write([]byte(http.StatusText(http.StatusInternalServerError) + "\n"))
  380. return
  381. }
  382. var sessioncookie http.Cookie
  383. if Configuration.Securecookies {
  384. sessioncookie = http.Cookie{
  385. Name: "sessionid",
  386. Value: sessionid,
  387. Path: "/",
  388. SameSite: http.SameSiteStrictMode,
  389. Secure: true,
  390. }
  391. } else {
  392. sessioncookie = http.Cookie{
  393. Name: "sessionid",
  394. Value: sessionid,
  395. Path: "/",
  396. SameSite: http.SameSiteStrictMode,
  397. }
  398. }
  399. http.SetCookie(w, &sessioncookie)
  400. http.Redirect(w, r, "/managelocations.html", http.StatusSeeOther)
  401. return
  402. default:
  403. w.WriteHeader(http.StatusNotImplemented)
  404. w.Write([]byte(http.StatusText(http.StatusNotImplemented) + "\n"))
  405. }
  406. }
  407. func root(w http.ResponseWriter, r *http.Request){
  408. switch r.Method {
  409. case "GET":
  410. sessionid, err := r.Cookie("sessionid")
  411. if err != nil {
  412. http.Redirect(w, r, "/login.html", http.StatusSeeOther)
  413. return
  414. }
  415. if check_sessionid(sessionid.Value) != true {
  416. http.Redirect(w, r, "/login.html", http.StatusSeeOther)
  417. return
  418. }
  419. http.Redirect(w, r, "/managelocations.html", http.StatusSeeOther)
  420. return
  421. default:
  422. w.WriteHeader(http.StatusNotImplemented)
  423. w.Write([]byte(http.StatusText(http.StatusNotImplemented) + "\n"))
  424. }
  425. }
  426. func authenticate(user string, password string) bool {
  427. bindusername := Configuration.Ldap.Binddn
  428. bindpassword := Configuration.Ldap.Bindpassword
  429. l, err := ldap.Dial("tcp", fmt.Sprintf("%s:%d", Configuration.Ldap.Host, Configuration.Ldap.Port))
  430. if err != nil {
  431. log.Print(err)
  432. return false
  433. }
  434. defer l.Close()
  435. // First bind with a read only user
  436. err = l.Bind(bindusername, bindpassword)
  437. if err != nil {
  438. log.Print(err)
  439. return false
  440. }
  441. // Search for the given username
  442. searchRequest := ldap.NewSearchRequest(
  443. Configuration.Ldap.Basedn,
  444. ldap.ScopeWholeSubtree, ldap.NeverDerefAliases, 0, 0, false,
  445. fmt.Sprintf("(&(" + Configuration.Ldap.Searchobject + ")(uid=%s))", user),
  446. []string{"dn"},
  447. nil,
  448. )
  449. sr, err := l.Search(searchRequest)
  450. if err != nil {
  451. log.Print(err)
  452. return false
  453. }
  454. if len(sr.Entries) != 1 {
  455. log.Print("User does not exist or too many entries returned")
  456. log.Print(sr.Entries)
  457. return false
  458. }
  459. userdn := sr.Entries[0].DN
  460. // Bind as the user to verify their password
  461. err = l.Bind(userdn, password)
  462. if err != nil {
  463. log.Print(err)
  464. return false
  465. }
  466. // Rebind as the read only user for any further queries
  467. err = l.Bind(bindusername, bindpassword)
  468. if err != nil {
  469. log.Print(err)
  470. return false
  471. }
  472. return true
  473. }
  474. func azureredirect() (string, error) {
  475. nonce, err := genrandomstring(8)
  476. if err != nil {
  477. return "", err
  478. }
  479. state, err := genrandomstring(8)
  480. if err != nil {
  481. return "", err
  482. }
  483. err = Redis.Set("state-" + state, nonce, 60 * time.Second).Err()
  484. if err != nil {
  485. return "", err
  486. }
  487. return "https://login.microsoftonline.com/" + Configuration.Azuread.Tenantid + "/oauth2/v2.0/authorize?client_id=" + Configuration.Azuread.Clientid + "&response_type=id_token&scope=openid&nonce=" + nonce + "&redirect_uri=" + url.QueryEscape(Configuration.Azuread.Redirecturi) + "&response_mode=form_post&state=" + state, err
  488. }
  489. func validate_id_token(id_token string, state string) bool {
  490. token := strings.Split(id_token, ".")
  491. if len(token) != 3 {
  492. return false
  493. }
  494. token_header_json, err := base64.RawURLEncoding.DecodeString(token[0])
  495. if err != nil {
  496. return false
  497. }
  498. var token_header TokenHeader
  499. json.Unmarshal([]byte(token_header_json), &token_header)
  500. token_claims_json, err := base64.RawURLEncoding.DecodeString(token[1])
  501. if err != nil {
  502. return false
  503. }
  504. var token_claims TokenClaims
  505. json.Unmarshal([]byte(token_claims_json), &token_claims)
  506. expected_nonce, err := Redis.Get("state-" + state).Result()
  507. if err != nil {
  508. return false
  509. }
  510. if token_claims.Nonce != expected_nonce {
  511. return false
  512. }
  513. if token_claims.Audience != Configuration.Azuread.Clientid {
  514. return false
  515. }
  516. if token_claims.Issued > time.Now().Unix() {
  517. return false
  518. }
  519. if token_claims.NotBefore > time.Now().Unix() {
  520. return false
  521. }
  522. if token_claims.Expires <= time.Now().Unix() {
  523. return false
  524. }
  525. valid_signature := false
  526. for _, key := range Tenantkeys.Keys {
  527. if key.KeyID == token_header.KeyID {
  528. CertBytes, _ := pem.Decode([]byte("-----BEGIN CERTIFICATE-----\n" + key.X5c[0] + "\n-----END CERTIFICATE-----"))
  529. if CertBytes == nil {
  530. return false
  531. }
  532. Cert, err := x509.ParseCertificate(CertBytes.Bytes)
  533. if err != nil {
  534. return false
  535. }
  536. messagehash := crypto.SHA256.New()
  537. messagehash.Write([]byte(token[0] + "." + token[1]))
  538. signature, err := base64.RawURLEncoding.DecodeString(token[2])
  539. if err != nil {
  540. return false
  541. }
  542. err = rsa.VerifyPKCS1v15(Cert.PublicKey.(*rsa.PublicKey), crypto.SHA256, messagehash.Sum(nil), signature)
  543. if err != nil {
  544. return false
  545. }
  546. valid_signature = true
  547. }
  548. }
  549. if valid_signature {
  550. Redis.Del("state-" + state)
  551. return true
  552. }
  553. return false
  554. }
  555. func get_tenant_keys (tenant_id string) error {
  556. tenant_openid_configuration_url := "https://login.microsoftonline.com/" + tenant_id + "/v2.0/.well-known/openid-configuration"
  557. var jwks_uri OpenIDJWKS
  558. HttpClient := http.Client{
  559. Timeout: time.Second * 2,
  560. }
  561. request_config, err := http.NewRequest(http.MethodGet, tenant_openid_configuration_url, nil)
  562. if err != nil {
  563. return err
  564. }
  565. request_config.Header.Set("User-Agent", "Location Finder App")
  566. response_config, err := HttpClient.Do(request_config)
  567. if err != nil {
  568. return err
  569. }
  570. body_config, err := ioutil.ReadAll(response_config.Body)
  571. if err != nil {
  572. return err
  573. }
  574. err = json.Unmarshal(body_config, &jwks_uri)
  575. if err != nil {
  576. return err
  577. }
  578. request_keys, err := http.NewRequest(http.MethodGet, jwks_uri.Jwksuri, nil)
  579. if err != nil {
  580. return err
  581. }
  582. request_keys.Header.Set("User-Agent", "Location Finder App")
  583. response_keys, err := HttpClient.Do(request_keys)
  584. if err != nil {
  585. return err
  586. }
  587. body_keys, err := ioutil.ReadAll(response_keys.Body)
  588. if err != nil {
  589. return err
  590. }
  591. err = json.Unmarshal(body_keys, &Tenantkeys)
  592. if err != nil {
  593. return err
  594. }
  595. return nil
  596. }
  597. func check_sessionid(sessionid string) bool {
  598. _, err := Redis.Get("session-" + sessionid).Result()
  599. if err != nil {
  600. return false
  601. }
  602. err = Redis.Expire("session-" + sessionid, 30 * time.Minute).Err()
  603. if err != nil {
  604. return false
  605. }
  606. return true
  607. }
  608. func check_item_key(id string, key string) bool {
  609. id_safe, _ := regexp.MatchString(`^[a-zA-Z0-9]{10}$`, id)
  610. if id_safe != true {
  611. return false
  612. }
  613. key_safe, _ := regexp.MatchString(`^[a-zA-Z0-9]{32}$`, key)
  614. if key_safe != true {
  615. return false
  616. }
  617. item, err := Redis.Get("key-" + id).Result()
  618. if err != nil {
  619. return false
  620. }
  621. if key != item {
  622. return false
  623. }
  624. return true
  625. }
  626. func write_key(id string, item float64) bool {
  627. err := Redis.Set(id, item, 30 * time.Minute).Err()
  628. if err != nil {
  629. return false
  630. }
  631. return true
  632. }
  633. func read_key(id string) (float64, bool) {
  634. item, err := Redis.Get(id).Result()
  635. if err != nil {
  636. return 0, false
  637. }
  638. item_float, conv_err := strconv.ParseFloat(item, 64)
  639. if conv_err != nil {
  640. return 0, false
  641. }
  642. return item_float, true
  643. }
  644. func genrandomstring(length int) (string, error) {
  645. const charset = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
  646. output := make([]byte, length)
  647. _, err := rand.Read(output)
  648. if err != nil {
  649. return "", err
  650. }
  651. for i, b := range output {
  652. output[i] = charset[b%byte(len(charset))]
  653. }
  654. return string(output), nil
  655. }
  656. func LoadConfiguration(file string) Config {
  657. var config Config
  658. configFile, err := os.Open(file)
  659. defer configFile.Close()
  660. if err != nil {
  661. fmt.Println(err.Error())
  662. }
  663. jsonParser := json.NewDecoder(configFile)
  664. jsonParser.Decode(&config)
  665. return config
  666. }
  667. func init() {
  668. config := flag.String("c", "./examples/config.json", "Config File location")
  669. flag.Parse()
  670. Configuration = LoadConfiguration(*config)
  671. Redis = redis.NewClient(&redis.Options{
  672. Addr: Configuration.Redis.Host + ":" + strconv.Itoa(Configuration.Redis.Port),
  673. Password: Configuration.Redis.Password,
  674. DB: Configuration.Redis.Database,
  675. })
  676. if Configuration.Azuread.Enabled {
  677. err := get_tenant_keys(Configuration.Azuread.Tenantid)
  678. if err != nil {
  679. os.Exit(1)
  680. }
  681. }
  682. }
  683. func schedule() {
  684. get_tenant_keys_schedule := time.NewTicker(time.Hour * 12)
  685. defer get_tenant_keys_schedule.Stop()
  686. for _ = range get_tenant_keys_schedule.C {
  687. _ = get_tenant_keys(Configuration.Azuread.Tenantid)
  688. }
  689. }
  690. func main() {
  691. if Configuration.Azuread.Enabled {
  692. go schedule()
  693. http.HandleFunc("/azureadlogin", azureadlogin)
  694. }
  695. http.HandleFunc("/managelocations.html", managelocations)
  696. http.HandleFunc("/setlocation.html", setlocation)
  697. http.HandleFunc("/getlocation.html", getlocation)
  698. http.HandleFunc("/api/createitem", api_createid)
  699. http.HandleFunc("/api/location", api_location)
  700. http.HandleFunc("/login.html", login)
  701. http.HandleFunc("/", root)
  702. http.ListenAndServe("127.0.0.1:8080", nil)
  703. }