2019-10-11 12:46:21 +03:00
|
|
|
/*
|
|
|
|
DESCRIPTION
|
|
|
|
request.go provides unexported functionality for creating and sending requests
|
|
|
|
required to configure settings of the GeoVision camera.
|
|
|
|
|
|
|
|
AUTHORS
|
|
|
|
Saxon A. Nelson-Milton <saxon@ausocean.org>
|
|
|
|
|
|
|
|
LICENSE
|
|
|
|
Copyright (C) 2019 the Australian Ocean Lab (AusOcean)
|
|
|
|
|
|
|
|
It is free software: you can redistribute it and/or modify them
|
|
|
|
under the terms of the GNU General Public License as published by the
|
|
|
|
Free Software Foundation, either version 3 of the License, or (at your
|
|
|
|
option) any later version.
|
|
|
|
|
|
|
|
It is distributed in the hope that it will be useful, but WITHOUT
|
|
|
|
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
|
|
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
|
|
|
for more details.
|
|
|
|
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
|
|
in gpl.txt. If not, see http://www.gnu.org/licenses.
|
|
|
|
*/
|
|
|
|
|
|
|
|
package gvctrl
|
|
|
|
|
|
|
|
import (
|
|
|
|
"bytes"
|
|
|
|
"fmt"
|
|
|
|
"io/ioutil"
|
|
|
|
"net/http"
|
|
|
|
"net/url"
|
|
|
|
"regexp"
|
|
|
|
"strconv"
|
|
|
|
)
|
|
|
|
|
2019-10-14 03:35:11 +03:00
|
|
|
// Relevant sub directories.
|
2019-10-11 12:46:21 +03:00
|
|
|
const (
|
2019-10-14 08:37:15 +03:00
|
|
|
loginSubDir = "/ssi.cgi/login.htm" // Used to get log-in page.
|
|
|
|
loggedInSubDir = "/LoginPC.cgi" // Used to submit log-in.
|
2019-10-14 03:35:11 +03:00
|
|
|
settingsSubDir = "/VideoSetting.cgi" // Used to submit settings.
|
2019-10-11 12:46:21 +03:00
|
|
|
)
|
|
|
|
|
2019-10-13 14:17:50 +03:00
|
|
|
// TODO: make this configurable.
|
2019-10-11 12:46:21 +03:00
|
|
|
const (
|
|
|
|
user = "admin"
|
|
|
|
pass = "admin"
|
|
|
|
)
|
|
|
|
|
2019-10-14 08:37:15 +03:00
|
|
|
// getLogin gets the log-in page and extracts the randomly generated cc values
|
2019-10-14 03:35:11 +03:00
|
|
|
// from which (as well as username and password) two hashes are generated.
|
|
|
|
// The generated hex is encoded into a url encoded form and returned as a string.
|
2019-10-14 08:35:38 +03:00
|
|
|
func getLogin(c *http.Client, id, host string) (string, error) {
|
2019-10-14 03:35:11 +03:00
|
|
|
req, err := http.NewRequest("GET", "https://"+host+loginSubDir, nil)
|
2019-10-11 12:46:21 +03:00
|
|
|
if err != nil {
|
2019-10-14 08:37:15 +03:00
|
|
|
return "", fmt.Errorf("can't create GET request for log-in page: %v", err)
|
2019-10-11 12:46:21 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
req.Header.Set("Connection", "keep-alive")
|
|
|
|
req.Header.Set("Cache-Control", "max-age=0")
|
|
|
|
req.Header.Set("Upgrade-Insecure-Requests", "1")
|
|
|
|
req.Header.Set("User-Agent", "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3865.90 Safari/537.36")
|
|
|
|
req.Header.Set("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3")
|
|
|
|
req.Header.Set("Accept-Encoding", "gzip, deflate")
|
|
|
|
req.Header.Set("Accept-Language", "en-GB,en-US;q=0.9,en;q=0.8")
|
|
|
|
req.Header.Set("Cookie", "CLIENT_ID="+id)
|
|
|
|
|
|
|
|
resp, err := c.Do(req)
|
|
|
|
if err != nil {
|
2019-10-14 08:37:15 +03:00
|
|
|
return "", fmt.Errorf("could not do GET request for log-in page: %v", err)
|
2019-10-11 12:46:21 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
defer resp.Body.Close()
|
|
|
|
body, err := ioutil.ReadAll(resp.Body)
|
|
|
|
if err != nil {
|
2019-10-14 08:37:15 +03:00
|
|
|
return "", fmt.Errorf("could not read response of GET request for log-in page: %v", err)
|
2019-10-11 12:46:21 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
// Find the CC values in the source of the response.
|
|
|
|
// These are used in calculation of the md5 hashes for the form submitted at
|
2019-10-14 08:37:15 +03:00
|
|
|
// log-in.
|
2019-10-11 12:46:21 +03:00
|
|
|
var cc [2]string
|
|
|
|
for i := range cc {
|
|
|
|
regStr := "cc" + strconv.Itoa(i+1) + "=\".{4}\""
|
|
|
|
exp := regexp.MustCompile(regStr).FindString(string(body))
|
|
|
|
cc[i] = exp[5 : len(exp)-1]
|
|
|
|
}
|
|
|
|
|
2019-10-13 14:17:50 +03:00
|
|
|
f := url.Values{}
|
|
|
|
f.Set("grp", "-1")
|
|
|
|
f.Set("username", "")
|
|
|
|
f.Set("password", "")
|
|
|
|
f.Set("Apply", "Apply")
|
|
|
|
f.Set("umd5", md5Hex(cc[0]+user+cc[1]))
|
|
|
|
f.Set("pmd5", md5Hex(cc[1]+pass+cc[0]))
|
|
|
|
f.Set("browser", "1")
|
|
|
|
f.Set("is_check_OCX_OK", "0")
|
|
|
|
|
|
|
|
return f.Encode(), nil
|
2019-10-11 12:46:21 +03:00
|
|
|
}
|
|
|
|
|
2019-10-14 08:35:38 +03:00
|
|
|
// login will submit the form b generated by genLogin.
|
|
|
|
func login(c *http.Client, id, host, b string) error {
|
2019-10-14 03:35:11 +03:00
|
|
|
req, err := http.NewRequest("POST", "http://"+host+loggedInSubDir, bytes.NewBuffer([]byte(b)))
|
2019-10-11 12:46:21 +03:00
|
|
|
if err != nil {
|
2019-10-14 08:37:15 +03:00
|
|
|
return fmt.Errorf("could not create log-in request: %v", err)
|
2019-10-11 12:46:21 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
req.Header.Set("Connection", "keep-alive")
|
|
|
|
req.Header.Set("Content-Length", "142")
|
|
|
|
req.Header.Set("Cache-Control", "max-age=0")
|
2019-10-14 03:35:11 +03:00
|
|
|
req.Header.Set("Origin", "http://"+host)
|
2019-10-11 12:46:21 +03:00
|
|
|
req.Header.Set("Upgrade-Insecure-Requests", "1")
|
|
|
|
req.Header.Set("User-Agent", "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3865.90 Safari/537.36")
|
|
|
|
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
|
|
|
|
req.Header.Set("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3")
|
2019-10-14 03:35:11 +03:00
|
|
|
req.Header.Set("Referer", "http://"+host+"/ssi.cgi/Login.htm")
|
2019-10-11 12:46:21 +03:00
|
|
|
req.Header.Set("Accept-Encoding", "gzip, deflate")
|
|
|
|
req.Header.Set("Accept-Language", "en-GB,en-US;q=0.9,en;q=0.8")
|
|
|
|
req.Header.Set("Cookie", "CLIENT_ID="+id+"; CLIENT_ID="+id)
|
|
|
|
|
|
|
|
_, err = c.Do(req)
|
|
|
|
if err != nil {
|
2019-10-14 08:37:15 +03:00
|
|
|
return fmt.Errorf("could not do log-in request: %v", err)
|
2019-10-11 12:46:21 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2019-10-14 03:35:11 +03:00
|
|
|
// submitSettings will populate a url encoded form using s and submit the
|
|
|
|
// settings to the server.
|
2019-10-11 12:46:21 +03:00
|
|
|
func submitSettings(c *http.Client, id, host string, s settings) error {
|
2019-10-13 05:12:31 +03:00
|
|
|
fBytes := []byte(populateForm(s).Encode())
|
2019-10-14 03:35:11 +03:00
|
|
|
req, err := http.NewRequest("POST", "http://"+host+settingsSubDir, bytes.NewReader(fBytes))
|
2019-10-11 12:46:21 +03:00
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("could not create settings submit request: %v", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
req.Header.Set("Connection", "keep-alive")
|
|
|
|
req.Header.Set("Content-Length", strconv.Itoa(len(fBytes)))
|
|
|
|
req.Header.Set("Cache-Control", "max-age=0")
|
2019-10-14 03:35:11 +03:00
|
|
|
req.Header.Set("Origin", "http://"+host)
|
2019-10-11 12:46:21 +03:00
|
|
|
req.Header.Set("Upgrade-Insecure-Requests", "1")
|
|
|
|
req.Header.Set("User-Agent", "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3865.90 Safari/537.36")
|
|
|
|
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
|
|
|
|
req.Header.Set("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3")
|
2019-10-14 03:35:11 +03:00
|
|
|
req.Header.Set("Referer", "http://"+host+"/ssi.cgi/VideoSettingSub.htm?cam=2")
|
2019-10-11 12:46:21 +03:00
|
|
|
req.Header.Set("Accept-Encoding", "gzip, deflate")
|
|
|
|
req.Header.Set("Accept-Language", "en-GB,en-US;q=0.9,en;q=0.8")
|
|
|
|
req.Header.Set("Cookie", "CLIENT_ID="+id)
|
|
|
|
|
|
|
|
// NB: not capturing error, as we always get one here for some reason.
|
|
|
|
// TODO: figure out why. Does not affect submission.
|
|
|
|
c.Do(req)
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|