// 列舉 PChome 網站的 DNSSEC 記錄。 func (ds *DNSSECService) List(zone string) ([]DNSSEC, error) { if len(zone) == 0 { logger.Printf("%s has empty zone name.", alu.Caller()) } urlstr := "http://myname.pchome.com.tw/manage/set_dnssec.htm?dn=" + zone req, err := http.NewRequest("GET", urlstr, nil) if err != nil { logger.Printf("%s creates http request failed, %s.", alu.Caller(), err.Error()) return nil, errors.New("Cannot create a http request.") } ds.Service.SetCookie(req) resp, err := http.DefaultClient.Do(req) if err != nil { logger.Printf("%s requesting failed, %s.", alu.Caller(), err.Error()) return nil, errors.New("Having http requesting failed.") } b, err := ioutil.ReadAll(resp.Body) if err != nil { logger.Printf("%s reads http body failed, %s.", alu.Caller(), err.Error()) return nil, errors.New("Reads http body failed.") } resp.Body.Close() slice, err := ds.parse(b) if err != nil { return nil, err } return slice, nil }
func (mp *MovableProperty) getPage() string { urlStr := fmt.Sprintf("http://www.tpkonsale.moj.gov.tw/sale/sale1QryM.asp?pageno=%d", mp.PageNo) resp, err := http.DefaultClient.Get(urlStr) if err != nil { log.Printf("%s has error, %s", alu.Caller(), err.Error()) return "" } b, err := ioutil.ReadAll(resp.Body) if err != nil { log.Printf("%s has error, %s", alu.Caller(), err.Error()) return "" } resp.Body.Close() cd, err := iconv.Open("utf-8//ignore", "big5") if err != nil { log.Printf("%s has error, %s", alu.Caller(), err.Error()) return "" } utf8 := cd.ConvString(string(b)) return utf8 }
// 移除 DNSSEC 記錄。 func (ds *DNSSECService) Delete(zone string, keyTag uint16, algorithm uint8, digest string) error { ds.cs = NewConfigService() config, err := ds.cs.Read() if err != nil { return err } ds.config = config // Zone if _, ok := ds.config.Zones[zone]; !ok { logger.Printf("%s has no matched zone name, %s.", alu.Caller(), zone) return errors.New("No matched zone name.") } zoneObj := ds.config.Zones[zone] ds.zone = zone // Find existed records. found := false for i, dnssec := range zoneObj.DNSSEC { if dnssec.KeyTag == keyTag && dnssec.Algorithm == algorithm && dnssec.Digest == digest { found = true zoneObj.DNSSEC = append(zoneObj.DNSSEC[:i], zoneObj.DNSSEC[i+1:]...) ds.config.Zones[zone] = zoneObj ds.save() break } } if !found { logger.Printf("%s has no matched DNSSEC record.", alu.Caller()) return errors.New("No matched DNSSEC record.") } return nil }
// 移除組態檔案。 func (cs *ConfigService) Remove() error { err := os.Remove(DefaultConfigPath) if err != nil { logger.Printf("%s remove the configuration file failed, %s.", alu.Caller(), err.Error()) return errors.New("Failed to remove the configuration file.") } logger.Printf("%s remove the configuration file successfully", alu.Caller()) return nil }
// 初始全新組態。 func (cs *ConfigService) initNew() error { config := Config{ UpdatedAt: time.Now().Unix(), Zones: make(map[string]Zone), } // Basic info fmt.Print("Paste your email here: ") _, err := fmt.Scanln(&config.Email) if err != nil { logger.Printf("%s scan email string failed, %s.", alu.Caller(), err.Error()) return errors.New("Scan email string failed.") } if len(config.Email) == 0 { logger.Printf("%s has empty email.", alu.Caller()) return errors.New("Empty email.") } fmt.Print("Paste your password here: ") _, err = fmt.Scanln(&config.Password) if err != nil { logger.Printf("%s scan password string failed, %s.", alu.Caller(), err.Error()) return errors.New("Scan password string failed.") } if len(config.Password) == 0 { logger.Printf("%s has empty password.", alu.Caller()) return errors.New("Empty password.") } key, err := cs.DoGetKey(config.Email, config.Password) if err != nil { return err } if len(key) == 0 { logger.Printf("%s gets a empty key.", alu.Caller()) return errors.New("Your email or password is wrong.") } // Zones & Records zones, err := cs.UpdateZones(NewService(key)) if err != nil { return err } else { config.Zones = zones if err = cs.Save(&config); err != nil { return err } } return nil }
// 讀取本地組態。 func (cs *ConfigService) Read() (Config, error) { b, err := ioutil.ReadFile(DefaultConfigPath) if err != nil { logger.Printf("%s read configuration file failed, %s.", alu.Caller(), err.Error()) return Config{}, errors.New("Read configuration file failed.") } var config Config err = json.Unmarshal(b, &config) if err != nil { logger.Printf("%s unmarshal json failed, %s.", alu.Caller(), err.Error()) return config, errors.New("Unmarshal configuration json failed.") } return config, nil }
// 更新 zone 內容。 func (cs *ConfigService) UpdateZones(s *Service) (map[string]Zone, error) { zones := s.NewZoneService().List().Do() keys := make([]string, 0) for k, _ := range zones { keys = append(keys, k) } sort.Strings(keys) ns := s.NewNSService() ds := s.NewDNSSECService() zone := make(map[string]Zone) for k, v := range keys { logger.Printf("%s received %s dns records. %d/%d) ", alu.Caller(), v, k+1, len(zones)) fmt.Printf("%d/%d) Received %s dns records.\n", k+1, len(zones), v) nsSlice, err := ns.List(v) if err != nil { return nil, err } dnssecSlice, err := ds.List(v) if err != nil { return nil, err } zone[v] = Zone{ NS: nsSlice, DNSSEC: dnssecSlice, } } return zone, nil }
func (r *Robots) IsAllowURLString(ua string, u string) bool { u1, err := url.Parse(u) if err != nil { log.Panicf("%s has error, %s.", alu.Caller(), err.Error()) } return r.IsAllowURL(ua, u1) }
// 取得服務。 func NewService(key string) *Service { if len(key) == 0 { logger.Printf("%s has empty key.", alu.Caller()) } return &Service{ Key: key, Logger: alu.NewLogger("log"), } }
// 執行 zone 列舉調用。 func (zlc *ZoneListCall) Do() map[string]Zone { urlstr := ENDPOINT + "/index.htm" req, err := http.NewRequest("GET", urlstr, nil) if err != nil { logger.Printf("%s creates request failed, %s.", alu.Caller(), err.Error()) } zlc.Service.SetCookie(req) resp, err := http.DefaultClient.Do(req) if err != nil { logger.Printf("%s requesting failed, %s.", alu.Caller(), err.Error()) } b, err := ioutil.ReadAll(resp.Body) if err != nil { logger.Printf("%s requesting failed, %s.", alu.Caller(), err.Error()) } resp.Body.Close() return zlc.Parse(b) }
// 初始組態服務 func (cs *ConfigService) Init() error { b, err := ioutil.ReadFile(DefaultConfigPath) if err != nil { if os.IsNotExist(err) { if err := cs.initNew(); err != nil { return err } } else { logger.Printf("%s read config file failed, %s.", alu.Caller(), err.Error()) } } var config Config err = json.Unmarshal(b, &config) if err != nil { logger.Printf("%s unmarshal json failed, %s.", alu.Caller(), err.Error()) } return nil }
// 登出 PChome 網站。 func (cs *ConfigService) Logout() error { if len(cs.Service.Key) == 0 { return errors.New("Empty access token.") } urlstr := "https://login.pchome.com.tw/adm/logout.php" req, err := http.NewRequest("GET", urlstr, nil) if err != nil { logger.Printf("%s creates http request failed, %s.", alu.Caller(), err.Error()) return errors.New("Cannot create a http request.") } cs.Service.SetCookie(req) _, err = http.DefaultClient.Do(req) if err != nil { logger.Printf("%s requesting failed, %s.", alu.Caller(), err.Error()) return errors.New("Cannot create a http request.") } return nil }
// 添加 DNSSEC 記錄。 func (ds *DNSSECService) Add(zone string, keyTag uint16, algorithm uint8, digest string) error { ds.cs = NewConfigService() config, err := ds.cs.Read() if err != nil { return err } ds.config = config // Zone if _, ok := ds.config.Zones[zone]; !ok { logger.Printf("%s has no such zone name, %s.", alu.Caller(), zone) return errors.New("No such zone name") } zoneObj := ds.config.Zones[zone] ds.zone = zone // Max records count. if len(zoneObj.DNSSEC) == 5 { logger.Printf("%s, the zone(%s) has reached the max DNESEC records count 5.", alu.Caller(), zone) return errors.New("The DNSSEC records of this zone is reaching the max count 5, delete some records first.\n") } // Find existed records. for _, dnssec := range zoneObj.DNSSEC { if dnssec.KeyTag == keyTag && dnssec.Algorithm == algorithm && dnssec.Digest == digest { logger.Printf("%s has duplicated.") return errors.New("Duplicated record.") } } record := DNSSEC{ KeyTag: keyTag, Algorithm: algorithm, Digest: digest, } zoneObj.DNSSEC = append(zoneObj.DNSSEC, record) ds.config.Zones[ds.zone] = zoneObj ds.save() return nil }
// 解析 PChome DNSSEC 網頁。 func (ds *DNSSECService) parse(raw []byte) ([]DNSSEC, error) { if len(raw) == 0 { logger.Printf("%s has empty raw.", alu.Caller()) return nil, errors.New("Empty content to parse.") } reKeyTag := regexp.MustCompile(`KeyTag\d" value="(\d{1,6})`) keyTags := reKeyTag.FindAllStringSubmatch(string(raw), -1) reAlgorithm := regexp.MustCompile(`alg\d" value="(\d{1,3})`) algorithms := reAlgorithm.FindAllStringSubmatch(string(raw), -1) reDigest := regexp.MustCompile(`DS\d" value="([\d|\w]+)`) digests := reDigest.FindAllStringSubmatch(string(raw), -1) if len(keyTags) != len(algorithms) && len(algorithms) != len(digests) { logger.Printf("%s has difference results.", alu.Caller()) return nil, errors.New("DNSSEC data does not match regex patterns.") } records := make([]DNSSEC, 0) for i := 0; i < len(keyTags); i++ { keyTag, err := strconv.Atoi(keyTags[i][1]) if err != nil { logger.Printf("%s parse string(%s) failed, %s.", alu.Caller(), keyTags[i][1], err.Error()) return nil, errors.New("Parse key tag failed.") } algorithm, err := strconv.Atoi(algorithms[i][1]) if err != nil { logger.Printf("%s parse string(%s) failed, %s.", alu.Caller(), algorithms[i][1], err.Error()) return nil, errors.New("Parse algorithm failed.") } records = append(records, DNSSEC{ KeyTag: uint16(keyTag), Algorithm: uint8(algorithm), Digest: digests[i][1], }) } return records, nil }
// 提交 DNSSEC 記錄到 PChome 網站。 func (ds *DNSSECService) save() error { reader := strings.NewReader(ds.preparePostData().Encode()) urlstr := ENDPOINT + "/set_dnssec.php" req, err := http.NewRequest("POST", urlstr, reader) if err != nil { logger.Printf("%s creates http request failed, %s.", alu.Caller(), err.Error()) return errors.New("Creating http request failed.") } req.Header.Add("Content-Type", "application/x-www-form-urlencoded") ds.Service.SetCookie(req) resp, err := http.DefaultClient.Do(req) if err != nil { logger.Printf("%s requesting failed, %s.", alu.Caller(), err.Error()) return errors.New("Having http requesting failed.") } resp.Body.Close() ds.cs.Save(&ds.config) return nil }
// 從網站取得 PCHome 存取鑰匙 func (cs *ConfigService) DoGetKey(email, password string) (string, error) { if len(email) == 0 { logger.Printf("%s has empty email.", alu.Caller()) return "", errors.New("Empty email.") } if len(password) == 0 { logger.Printf("%s has empty password.", alu.Caller()) return "", errors.New("Empty password.") } urlstr := "https://login.pchome.com.tw/adm/person_sell.htm" data := url.Values{ "mbrid": []string{email}, "mbrpass": []string{password}, "chan": []string{"P000007"}, "ltype": []string{"checklogin"}, } resp, err := http.DefaultClient.PostForm(urlstr, data) if err != nil { logger.Printf("%s http requesting failed, %s.", alu.Caller(), err.Error()) return "", errors.New("Http requesting failed.") } key := "" for _, cookie := range resp.Cookies() { if cookie.Name == "loginkuser" { key = cookie.Value break } } resp.Body.Close() return key, nil }
// 解析 zone 列舉調用結果。 func (zlc *ZoneListCall) Parse(raw []byte) map[string]Zone { zones := make(map[string]Zone) if len(raw) == 0 { logger.Printf("%s has empty raw.", alu.Caller()) return zones } re := regexp.MustCompile(`\?dn=(.*)">進入`) if !re.Match(raw) { return zones } ms := re.FindAllStringSubmatch(string(raw), -1) for _, v := range ms { zones[v[1]] = Zone{} } return zones }
func (mp *MovableProperty) Get() { html := mp.getPage() reAmount := regexp.MustCompile(`共(\d+)筆`) amountStr := reAmount.FindAllStringSubmatch(html, -1) amount, err := strconv.Atoi(amountStr[0][1]) if err != nil { log.Printf("%s has error, %s", alu.Caller(), err.Error()) return } mp.Amount = amount fmt.Printf("%d items.\n", mp.Amount) for mp.PageNo <= uint8(math.Ceil(float64(mp.Amount) / 50.0)) { mp.page(html) fmt.Printf("pageNo: %d, items: %d, amount: %d\n", mp.PageNo, len(mp.Items), mp.Amount) mp.PageNo++ html = mp.getPage() } }
// 儲存組態內容。 func (cs *ConfigService) Save(config *Config) error { if config == nil { logger.Printf("%s has nil config.", alu.Caller()) return errors.New("nil config.") } // Write b, err := json.MarshalIndent(config, "", " ") if err != nil { logger.Printf("%s marshal json failed, %s.", alu.Caller(), err.Error()) return errors.New("Marshal json failed.") } file, err := os.OpenFile(DefaultConfigPath, os.O_RDWR, os.ModePerm) if err != nil { if os.IsNotExist(err) { file, err = os.Create(DefaultConfigPath) if err != nil { logger.Printf("%s creates configuration file failed, %s.", alu.Caller(), err.Error()) return errors.New("Create configuration file failed.") } else { file, err = os.OpenFile(DefaultConfigPath, os.O_RDWR, os.ModePerm) if err != nil { logger.Printf("%s opens configuration file failed, %s.", alu.Caller(), err.Error()) return errors.New("Open configuration file failed.") } } } else { logger.Printf("%s opens configuration file failed, %s.", alu.Caller(), err.Error()) return errors.New("Open configuration file failed.") } } _, err = file.Write(b) if err != nil { file.Close() logger.Printf("%s write configuration file failed, %s.", alu.Caller(), err.Error()) return errors.New("Writing configuration file failed.") } logger.Printf("%s write configuration file successfully.", alu.Caller()) file.Close() return nil }