pax_global_header00006660000000000000000000000064137150577040014523gustar00rootroot0000000000000052 comment=176a855091538b1f3e08aecba092796cdaf2c8a7 goinwx-0.8.1/000077500000000000000000000000001371505770400130445ustar00rootroot00000000000000goinwx-0.8.1/.gitignore000066400000000000000000000000371371505770400150340ustar00rootroot00000000000000*.iml .idea vendor dist builds goinwx-0.8.1/.golangci.toml000066400000000000000000000016211371505770400156020ustar00rootroot00000000000000[run] deadline = "5m" skip-files = [] [linters-settings] [linters-settings.govet] check-shadowing = true [linters-settings.gocyclo] min-complexity = 12.0 [linters-settings.maligned] suggest-new = true [linters-settings.goconst] min-len = 3.0 min-occurrences = 3.0 [linters-settings.misspell] locale = "US" [linters] enable-all = true disable = [ "maligned", "lll", "dupl", "gomnd", "stylecheck", "wsl", "goerr113", "testpackage", "nlreturn", ] [issues] exclude-use-default = false max-per-linter = 0 max-same-issues = 0 exclude = [ "`(methodDomainGetRules|methodDomainLog|methodDomainPush|methodDomainRenew|methodDomainRestore|methodDomainStats|methodDomainTrade|methodDomainTransfer|methodDomainTransferOut|methodDomainUpdate)` is unused", "`(methodNameserverUpdate|methodNameserverDelete)` is unused", ] goinwx-0.8.1/.travis.yml000066400000000000000000000007261371505770400151620ustar00rootroot00000000000000language: go go: - 1.14.x - 1.x env: - GO111MODULE=on notifications: email: on_success: never on_failure: change before_install: # Install linters and misspell - curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b $(go env GOPATH)/bin ${GOLANGCI_LINT_VERSION} - golangci-lint --version install: - go mod tidy - git diff --exit-code go.mod - git diff --exit-code go.sum - go mod download goinwx-0.8.1/LICENSE000066400000000000000000000020471371505770400140540ustar00rootroot00000000000000MIT License Copyright (c) 2017 Andrew Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. goinwx-0.8.1/Makefile000066400000000000000000000005401371505770400145030ustar00rootroot00000000000000.PHONY: default clean check test fmt GOFILES := $(shell go list -f '{{range $$index, $$element := .GoFiles}}{{$$.Dir}}/{{$$element}}{{"\n"}}{{end}}' ./... | grep -v '/vendor/') default: clean check test build test: clean go test -v -cover ./... clean: rm -f cover.out build: go build fmt: gofmt -s -l -w $(GOFILES) check: golangci-lint run goinwx-0.8.1/README.md000066400000000000000000000056051371505770400143310ustar00rootroot00000000000000# INWX Go API client [![Build Status](https://travis-ci.com/nrdcg/goinwx.svg?branch=master)](https://travis-ci.com/nrdcg/goinwx) [![GoDoc](https://godoc.org/github.com/nrdcg/goinwx?status.svg)](https://godoc.org/github.com/nrdcg/goinwx) [![Go Report Card](https://goreportcard.com/badge/github.com/nrdcg/goinwx)](https://goreportcard.com/report/github.com/nrdcg/goinwx) This go library implements some parts of the official INWX XML-RPC API. ## API ```go package main import ( "log" "github.com/nrdcg/goinwx" ) func main() { client := goinwx.NewClient("username", "password", &goinwx.ClientOptions{Sandbox: true}) _, err := client.Account.Login() if err != nil { log.Fatal(err) } defer func() { if err := client.Account.Logout(); err != nil { log.Printf("inwx: failed to logout: %v", err) } }() var request = &goinwx.NameserverRecordRequest{ Domain: "domain.com", Name: "foo.domain.com.", Type: "TXT", Content: "aaa", TTL: 300, } _, err = client.Nameservers.CreateRecord(request) if err != nil { log.Fatal(err) } } ``` ### Using 2FA If it is desired to use 2FA without manual entering the TOTP every time, you must set the parameter `otp-key` to the secret that is shown during the setup of 2FA for you INWX account. Otherwise, you can skip `totp.GenerateCode` step and enter the verification code of the Google Authenticator app every time manually. The `otp-key` looks something like `EELTWFL55ESIHPTJAAHBCY7LXBZARUOJ`. ```go package main import ( "log" "time" "github.com/nrdcg/goinwx" "github.com/pquerna/otp/totp" ) func main() { client := goinwx.NewClient("username", "password", &goinwx.ClientOptions{Sandbox: true}) resp, err := client.Account.Login() if err != nil { log.Fatal(err) } if resp.TFA != "GOOGLE-AUTH" { log.Fatal("unsupported 2 Factor Authentication") } tan, err := totp.GenerateCode("otp-key", time.Now()) if err != nil { log.Fatal(err) } err = client.Account.Unlock(tan) if err != nil { log.Fatal(err) } defer func() { if err := client.Account.Logout(); err != nil { log.Printf("inwx: failed to logout: %v", err) } }() request := &goinwx.NameserverRecordRequest{ Domain: "domain.com", Name: "foo.domain.com.", Type: "TXT", Content: "aaa", TTL: 300, } _, err = client.Nameservers.CreateRecord(request) if err != nil { log.Fatal(err) } } ``` ## Supported Features Full API documentation can be found [here](https://www.inwx.de/en/help/apidoc). The following parts are implemented: * Account * Login * Logout * Lock * Unlock (with mobile TAN) * Domains * Check * Register * Delete * Info * GetPrices * List * Whois * Update * Nameservers * Check * Create * Info * List * CreateRecord * UpdateRecord * DeleteRecord * FindRecordById * Contacts * List * Info * Create * Update * Delete ## Contributions Your contributions are very appreciated. goinwx-0.8.1/account.go000066400000000000000000000030041371505770400150240ustar00rootroot00000000000000package goinwx import "github.com/mitchellh/mapstructure" const ( methodAccountLogin = "account.login" methodAccountLogout = "account.logout" methodAccountLock = "account.lock" methodAccountUnlock = "account.unlock" ) // AccountService API access to Account. type AccountService service // Login Account login. func (s *AccountService) Login() (*LoginResponse, error) { req := s.client.NewRequest(methodAccountLogin, map[string]interface{}{ "user": s.client.username, "pass": s.client.password, }) resp, err := s.client.Do(*req) if err != nil { return nil, err } var result LoginResponse err = mapstructure.Decode(*resp, &result) if err != nil { return nil, err } return &result, nil } // Logout Account logout. func (s *AccountService) Logout() error { req := s.client.NewRequest(methodAccountLogout, nil) _, err := s.client.Do(*req) return err } // Lock Account lock. func (s *AccountService) Lock() error { req := s.client.NewRequest(methodAccountLock, nil) _, err := s.client.Do(*req) return err } // Unlock Account unlock. func (s *AccountService) Unlock(tan string) error { req := s.client.NewRequest(methodAccountUnlock, map[string]interface{}{ "tan": tan, }) _, err := s.client.Do(*req) return err } // LoginResponse API model. type LoginResponse struct { CustomerID int64 `mapstructure:"customerId"` AccountID int64 `mapstructure:"accountId"` TFA string `mapstructure:"tfa"` BuildDate string `mapstructure:"builddate"` Version string `mapstructure:"version"` } goinwx-0.8.1/contact.go000066400000000000000000000074231371505770400150340ustar00rootroot00000000000000package goinwx import ( "github.com/fatih/structs" "github.com/mitchellh/mapstructure" ) const ( methodContactInfo = "contact.info" methodContactList = "contact.list" methodContactCreate = "contact.create" methodContactDelete = "contact.delete" methodContactUpdate = "contact.update" ) // ContactService API access to Contact. type ContactService service // Create Creates a contact. func (s *ContactService) Create(request *ContactCreateRequest) (int, error) { req := s.client.NewRequest(methodContactCreate, structs.Map(request)) resp, err := s.client.Do(*req) if err != nil { return 0, err } result := make(map[string]int) err = mapstructure.Decode(*resp, &result) if err != nil { return 0, err } return result["id"], nil } // Delete Deletes a contact. func (s *ContactService) Delete(roID int) error { req := s.client.NewRequest(methodContactDelete, map[string]interface{}{ "id": roID, }) _, err := s.client.Do(*req) return err } // Update Updates a contact. func (s *ContactService) Update(request *ContactUpdateRequest) error { req := s.client.NewRequest(methodContactUpdate, structs.Map(request)) _, err := s.client.Do(*req) return err } // Info Get information about a contact. func (s *ContactService) Info(contactID int) (*ContactInfoResponse, error) { requestMap := make(map[string]interface{}) requestMap["wide"] = 1 if contactID != 0 { requestMap["id"] = contactID } req := s.client.NewRequest(methodContactInfo, requestMap) resp, err := s.client.Do(*req) if err != nil { return nil, err } result := ContactInfoResponse{} err = mapstructure.Decode(*resp, &result) if err != nil { return nil, err } return &result, nil } // List Search contacts. func (s *ContactService) List(search string) (*ContactListResponse, error) { requestMap := make(map[string]interface{}) if search != "" { requestMap["search"] = search } req := s.client.NewRequest(methodContactList, requestMap) resp, err := s.client.Do(*req) if err != nil { return nil, err } result := ContactListResponse{} err = mapstructure.Decode(*resp, &result) if err != nil { return nil, err } return &result, nil } // ContactCreateRequest API model. type ContactCreateRequest struct { Type string `structs:"type"` Name string `structs:"name"` Org string `structs:"org,omitempty"` Street string `structs:"street"` City string `structs:"city"` PostalCode string `structs:"pc"` StateProvince string `structs:"sp,omitempty"` CountryCode string `structs:"cc"` Voice string `structs:"voice"` Fax string `structs:"fax,omitempty"` Email string `structs:"email"` Remarks string `structs:"remarks,omitempty"` Protection bool `structs:"protection,omitempty"` Testing bool `structs:"testing,omitempty"` } // ContactUpdateRequest API model. type ContactUpdateRequest struct { ID int `structs:"id"` Name string `structs:"name,omitempty"` Org string `structs:"org,omitempty"` Street string `structs:"street,omitempty"` City string `structs:"city,omitempty"` PostalCode string `structs:"pc,omitempty"` StateProvince string `structs:"sp,omitempty"` CountryCode string `structs:"cc,omitempty"` Voice string `structs:"voice,omitempty"` Fax string `structs:"fax,omitempty"` Email string `structs:"email,omitempty"` Remarks string `structs:"remarks,omitempty"` Protection bool `structs:"protection,omitempty"` Testing bool `structs:"testing,omitempty"` } // ContactInfoResponse API model. type ContactInfoResponse struct { Contact Contact `mapstructure:"contact"` } // ContactListResponse API model. type ContactListResponse struct { Count int Contacts []Contact `mapstructure:"contact"` } goinwx-0.8.1/domain.go000066400000000000000000000252711371505770400146510ustar00rootroot00000000000000package goinwx import ( "errors" "time" "github.com/fatih/structs" "github.com/mitchellh/mapstructure" ) const ( methodDomainCheck = "domain.check" methodDomainCreate = "domain.create" methodDomainDelete = "domain.delete" methodDomainGetPrices = "domain.getPrices" methodDomainGetRules = "domain.getRules" methodDomainInfo = "domain.info" methodDomainList = "domain.list" methodDomainLog = "domain.log" methodDomainPush = "domain.push" methodDomainRenew = "domain.renew" methodDomainRestore = "domain.restore" methodDomainStats = "domain.stats" methodDomainTrade = "domain.trade" methodDomainTransfer = "domain.transfer" methodDomainTransferOut = "domain.transferOut" methodDomainUpdate = "domain.update" methodDomainWhois = "domain.whois" ) // DomainService API access to Domain. type DomainService service // Check Checks domains. func (s *DomainService) Check(domains []string) ([]DomainCheckResponse, error) { req := s.client.NewRequest(methodDomainCheck, map[string]interface{}{ "domain": domains, "wide": "2", }) resp, err := s.client.Do(*req) if err != nil { return nil, err } root := new(domainCheckResponseRoot) err = mapstructure.Decode(*resp, &root) if err != nil { return nil, err } return root.Domains, nil } // GetPrices Gets TLDS prices. func (s *DomainService) GetPrices(tlds []string) ([]DomainPriceResponse, error) { req := s.client.NewRequest(methodDomainGetPrices, map[string]interface{}{ "tld": tlds, "vat": false, }) resp, err := s.client.Do(*req) if err != nil { return nil, err } root := new(domainPriceResponseRoot) err = mapstructure.Decode(*resp, &root) if err != nil { return nil, err } return root.Prices, nil } // Register Register a domain. func (s *DomainService) Register(request *DomainRegisterRequest) (*DomainRegisterResponse, error) { req := s.client.NewRequest(methodDomainCreate, structs.Map(request)) resp, err := s.client.Do(*req) if err != nil { return nil, err } var result DomainRegisterResponse err = mapstructure.Decode(*resp, &result) if err != nil { return nil, err } return &result, nil } // Delete Deletes a domain. func (s *DomainService) Delete(domain string, scheduledDate time.Time) error { req := s.client.NewRequest(methodDomainDelete, map[string]interface{}{ "domain": domain, "scDate": scheduledDate.Format(time.RFC3339), }) _, err := s.client.Do(*req) return err } // Info Gets information about a domain. func (s *DomainService) Info(domain string, roID int) (*DomainInfoResponse, error) { req := s.client.NewRequest(methodDomainInfo, map[string]interface{}{ "domain": domain, "wide": "2", }) if roID != 0 { req.Args["roId"] = roID } resp, err := s.client.Do(*req) if err != nil { return nil, err } var result DomainInfoResponse err = mapstructure.Decode(*resp, &result) if err != nil { return nil, err } return &result, nil } // List List domains. func (s *DomainService) List(request *DomainListRequest) (*DomainList, error) { if request == nil { return nil, errors.New("request can't be nil") } requestMap := structs.Map(request) requestMap["wide"] = "2" req := s.client.NewRequest(methodDomainList, requestMap) resp, err := s.client.Do(*req) if err != nil { return nil, err } var result DomainList err = mapstructure.Decode(*resp, &result) if err != nil { return nil, err } return &result, nil } // Whois Whois about a domains. func (s *DomainService) Whois(domain string) (string, error) { req := s.client.NewRequest(methodDomainWhois, map[string]interface{}{ "domain": domain, }) resp, err := s.client.Do(*req) if err != nil { return "", err } var result map[string]string err = mapstructure.Decode(*resp, &result) if err != nil { return "", err } return result["whois"], nil } // Update Updates domain information. func (s *DomainService) Update(request *DomainUpdateRequest) (float32, error) { req := s.client.NewRequest(methodDomainUpdate, structs.Map(request)) resp, err := s.client.Do(*req) if err != nil { return 0, err } var result DomainUpdateResponse err = mapstructure.Decode(*resp, &result) if err != nil { return 0, err } return result.Price, nil } type domainCheckResponseRoot struct { Domains []DomainCheckResponse `mapstructure:"domain"` } // DomainCheckResponse API model. type DomainCheckResponse struct { Available int `mapstructure:"avail"` Status string `mapstructure:"status"` Name string `mapstructure:"name"` Domain string `mapstructure:"domain"` TLD string `mapstructure:"tld"` CheckMethod string `mapstructure:"checkmethod"` Price float32 `mapstructure:"price"` CheckTime float32 `mapstructure:"checktime"` } type domainPriceResponseRoot struct { Prices []DomainPriceResponse `mapstructure:"price"` } // DomainPriceResponse API model. type DomainPriceResponse struct { Tld string `mapstructure:"tld"` Currency string `mapstructure:"currency"` CreatePrice float32 `mapstructure:"createPrice"` MonthlyCreatePrice float32 `mapstructure:"monthlyCreatePrice"` TransferPrice float32 `mapstructure:"transferPrice"` RenewalPrice float32 `mapstructure:"renewalPrice"` MonthlyRenewalPrice float32 `mapstructure:"monthlyRenewalPrice"` UpdatePrice float32 `mapstructure:"updatePrice"` TradePrice float32 `mapstructure:"tradePrice"` TrusteePrice float32 `mapstructure:"trusteePrice"` MonthlyTrusteePrice float32 `mapstructure:"monthlyTrusteePrice"` CreatePeriod int `mapstructure:"createPeriod"` TransferPeriod int `mapstructure:"transferPeriod"` RenewalPeriod int `mapstructure:"renewalPeriod"` TradePeriod int `mapstructure:"tradePeriod"` } // DomainRegisterRequest API model. type DomainRegisterRequest struct { Domain string `structs:"domain"` Period string `structs:"period,omitempty"` Registrant int `structs:"registrant"` Admin int `structs:"admin"` Tech int `structs:"tech"` Billing int `structs:"billing"` Nameservers []string `structs:"ns,omitempty"` TransferLock string `structs:"transferLock,omitempty"` RenewalMode string `structs:"renewalMode,omitempty"` WhoisProvider string `structs:"whoisProvider,omitempty"` WhoisURL string `structs:"whoisUrl,omitempty"` ScDate string `structs:"scDate,omitempty"` ExtDate string `structs:"extDate,omitempty"` Asynchron string `structs:"asynchron,omitempty"` Voucher string `structs:"voucher,omitempty"` Testing string `structs:"testing,omitempty"` } // DomainRegisterResponse API model. type DomainRegisterResponse struct { RoID int `mapstructure:"roId"` Price float32 `mapstructure:"price"` Currency string `mapstructure:"currency"` } // DomainInfoResponse API model. type DomainInfoResponse struct { RoID int `mapstructure:"roId"` Domain string `mapstructure:"domain"` DomainAce string `mapstructure:"domainAce"` Period string `mapstructure:"period"` CrDate time.Time `mapstructure:"crDate"` ExDate time.Time `mapstructure:"exDate"` UpDate time.Time `mapstructure:"upDate"` ReDate time.Time `mapstructure:"reDate"` ScDate time.Time `mapstructure:"scDate"` TransferLock int `mapstructure:"transferLock"` Status string `mapstructure:"status"` AuthCode string `mapstructure:"authCode"` RenewalMode string `mapstructure:"renewalMode"` TransferMode string `mapstructure:"transferMode"` Registrant int `mapstructure:"registrant"` Admin int `mapstructure:"admin"` Tech int `mapstructure:"tech"` Billing int `mapstructure:"billing"` Nameservers []string `mapstructure:"ns"` NoDelegation int `mapstructure:"noDelegation"` Contacts map[string]Contact `mapstructure:"contact"` } // Contact API model. type Contact struct { RoID int `mapstructure:"roId"` ID string `mapstructure:"id"` Type string `mapstructure:"type"` Name string `mapstructure:"name"` Org string `mapstructure:"org"` Street string `mapstructure:"street"` City string `mapstructure:"city"` PostalCode string `mapstructure:"pc"` StateProvince string `mapstructure:"sp"` Country string `mapstructure:"cc"` Phone string `mapstructure:"voice"` Fax string `mapstructure:"fax"` Email string `mapstructure:"email"` Remarks string `mapstructure:"remarks"` Protection string `mapstructure:"protection"` } // DomainListRequest API model. type DomainListRequest struct { Domain string `structs:"domain,omitempty"` RoID int `structs:"roId,omitempty"` Status int `structs:"status,omitempty"` Registrant int `structs:"registrant,omitempty"` Admin int `structs:"admin,omitempty"` Tech int `structs:"tech,omitempty"` Billing int `structs:"billing,omitempty"` RenewalMode int `structs:"renewalMode,omitempty"` TransferLock int `structs:"transferLock,omitempty"` NoDelegation int `structs:"noDelegation,omitempty"` Tag int `structs:"tag,omitempty"` Order int `structs:"order,omitempty"` Page int `structs:"page,omitempty"` PageLimit int `structs:"pagelimit,omitempty"` } // DomainList API model. type DomainList struct { Count int Domains []DomainInfoResponse `mapstructure:"domain"` } // DomainUpdateRequest API model. type DomainUpdateRequest struct { Domain string `structs:"domain"` Nameservers []string `structs:"ns,omitempty"` TransferLock int `structs:"transferLock,omitempty"` RenewalMode string `structs:"renewalMode,omitempty"` TransferMode string `structs:"transferMode,omitempty"` // unsupported fields: // registrant New owner contact handle id int false // admin New administrative contact handle id int false // tech New technical contact handle id int false // billing New billing contact handle id int false // authCode Authorization code (if supported) text64 false // scDate Time of scheduled execution timestamp false // whoisProvider Whois provider token0255 false // whoisUrl Whois url token0255 false // extData Domain extra data extData false // asynchron Asynchron domain update boolean false false // testing Execute command in testing mode boolean false false } // DomainUpdateResponse API model. type DomainUpdateResponse struct { Price float32 `mapstructure:"price"` } goinwx-0.8.1/go.mod000066400000000000000000000003411371505770400141500ustar00rootroot00000000000000module github.com/nrdcg/goinwx go 1.14 require ( github.com/fatih/structs v1.1.0 github.com/kolo/xmlrpc v0.0.0-20200310150728-e0350524596b github.com/mitchellh/mapstructure v1.3.3 golang.org/x/text v0.3.2 // indirect ) goinwx-0.8.1/go.sum000066400000000000000000000015011371505770400141740ustar00rootroot00000000000000github.com/fatih/structs v1.1.0 h1:Q7juDM0QtcnhCpeyLGQKyg4TOIghuNXrkL32pHAUMxo= github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M= github.com/kolo/xmlrpc v0.0.0-20200310150728-e0350524596b h1:DzHy0GlWeF0KAglaTMY7Q+khIFoG8toHP+wLFBVBQJc= github.com/kolo/xmlrpc v0.0.0-20200310150728-e0350524596b/go.mod h1:o03bZfuBwAXHetKXuInt4S7omeXUu62/A845kiycsSQ= github.com/mitchellh/mapstructure v1.3.3 h1:SzB1nHZ2Xi+17FP0zVQBHIZqvwRN9408fJO8h+eeNA8= github.com/mitchellh/mapstructure v1.3.3/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= goinwx-0.8.1/goinwx.go000066400000000000000000000056261371505770400147170ustar00rootroot00000000000000package goinwx import ( "net/url" "github.com/kolo/xmlrpc" ) // API information. const ( APIBaseURL = "https://api.domrobot.com/xmlrpc/" APISandboxBaseURL = "https://api.ote.domrobot.com/xmlrpc/" APILanguage = "en" ) // Client manages communication with INWX API. type Client struct { // HTTP client used to communicate with the INWX API. RPCClient *xmlrpc.Client // API username and password username string password string lang string common service // Reuse a single struct instead of allocating one for each service on the heap. // Services used for communicating with the API Account *AccountService Domains *DomainService Nameservers *NameserverService Contacts *ContactService } type service struct { client *Client } // ClientOptions Options of the API client. type ClientOptions struct { Sandbox bool // Language of the return message. (en/de/es) Lang string // Base URL for API requests (only for client testing purpose). BaseURL *url.URL } // Request The representation of an API request. type Request struct { ServiceMethod string Args map[string]interface{} } // NewClient returns a new INWX API client. func NewClient(username, password string, opts *ClientOptions) *Client { baseURL := getBaseURL(opts).String() rpcClient, _ := xmlrpc.NewClient(baseURL, nil) client := &Client{ RPCClient: rpcClient, username: username, password: password, lang: APILanguage, } if opts != nil && opts.Lang != "" { client.lang = opts.Lang } client.common.client = client client.Account = (*AccountService)(&client.common) client.Domains = (*DomainService)(&client.common) client.Nameservers = (*NameserverService)(&client.common) client.Contacts = (*ContactService)(&client.common) return client } // NewRequest creates an API request. func (c *Client) NewRequest(serviceMethod string, args map[string]interface{}) *Request { if args != nil { args["lang"] = APILanguage } return &Request{ServiceMethod: serviceMethod, Args: args} } // Do sends an API request and returns the API response. func (c *Client) Do(req Request) (*map[string]interface{}, error) { var resp Response err := c.RPCClient.Call(req.ServiceMethod, req.Args, &resp) if err != nil { return nil, err } return &resp.ResponseData, checkResponse(&resp) } // checkResponse checks the API response for errors, and returns them if present. func checkResponse(r *Response) error { if c := r.Code; c >= 1000 && c <= 1500 { return nil } return &ErrorResponse{Code: r.Code, Message: r.Message, Reason: r.Reason, ReasonCode: r.ReasonCode} } func getBaseURL(opts *ClientOptions) *url.URL { var useSandbox bool if opts != nil { useSandbox = opts.Sandbox } var baseURL *url.URL if useSandbox { baseURL, _ = url.Parse(APISandboxBaseURL) } else { baseURL, _ = url.Parse(APIBaseURL) } if opts != nil && opts.BaseURL != nil { baseURL = opts.BaseURL } return baseURL } goinwx-0.8.1/nameserver.go000066400000000000000000000205231371505770400155440ustar00rootroot00000000000000package goinwx import ( "errors" "fmt" "time" "github.com/fatih/structs" "github.com/mitchellh/mapstructure" ) const ( methodNameserverCheck = "nameserver.check" methodNameserverCreate = "nameserver.create" methodNameserverCreateRecord = "nameserver.createRecord" methodNameserverDelete = "nameserver.delete" methodNameserverDeleteRecord = "nameserver.deleteRecord" methodNameserverInfo = "nameserver.info" methodNameserverList = "nameserver.list" methodNameserverUpdate = "nameserver.update" methodNameserverUpdateRecord = "nameserver.updateRecord" ) // NameserverService API access to Nameservers. type NameserverService service // Check Checks a domain on nameservers. func (s *NameserverService) Check(domain string, nameservers []string) (*NameserverCheckResponse, error) { req := s.client.NewRequest(methodNameserverCheck, map[string]interface{}{ "domain": domain, "ns": nameservers, }) resp, err := s.client.Do(*req) if err != nil { return nil, err } var result NameserverCheckResponse err = mapstructure.Decode(*resp, &result) if err != nil { return nil, err } return &result, nil } // Info Gets information. func (s *NameserverService) Info(request *NameserverInfoRequest) (*NamserverInfoResponse, error) { req := s.client.NewRequest(methodNameserverInfo, structs.Map(request)) resp, err := s.client.Do(*req) if err != nil { return nil, err } result := NamserverInfoResponse{} err = mapstructure.Decode(*resp, &result) if err != nil { return nil, err } return &result, nil } // List List nameservers for a domain. func (s *NameserverService) List(domain string) (*NamserverListResponse, error) { requestMap := map[string]interface{}{ "domain": "*", "wide": 2, } if domain != "" { requestMap["domain"] = domain } req := s.client.NewRequest(methodNameserverList, requestMap) resp, err := s.client.Do(*req) if err != nil { return nil, err } result := NamserverListResponse{} err = mapstructure.Decode(*resp, &result) if err != nil { return nil, err } return &result, nil } // Create Creates a nameserver. func (s *NameserverService) Create(request *NameserverCreateRequest) (int, error) { req := s.client.NewRequest(methodNameserverCreate, structs.Map(request)) resp, err := s.client.Do(*req) if err != nil { return 0, err } var result map[string]int err = mapstructure.Decode(*resp, &result) if err != nil { return 0, err } return result["roId"], nil } // CreateRecord Creates a DNS record. func (s *NameserverService) CreateRecord(request *NameserverRecordRequest) (int, error) { req := s.client.NewRequest(methodNameserverCreateRecord, structs.Map(request)) resp, err := s.client.Do(*req) if err != nil { return 0, err } var result map[string]int err = mapstructure.Decode(*resp, &result) if err != nil { return 0, err } return result["id"], nil } // UpdateRecord Updates a DNS record. func (s *NameserverService) UpdateRecord(recID int, request *NameserverRecordRequest) error { if request == nil { return errors.New("request can't be nil") } requestMap := structs.Map(request) requestMap["id"] = recID req := s.client.NewRequest(methodNameserverUpdateRecord, requestMap) _, err := s.client.Do(*req) if err != nil { return err } return nil } // DeleteRecord Deletes a DNS record. func (s *NameserverService) DeleteRecord(recID int) error { req := s.client.NewRequest(methodNameserverDeleteRecord, map[string]interface{}{ "id": recID, }) _, err := s.client.Do(*req) if err != nil { return err } return nil } // FindRecordByID Search a DNS record by ID. func (s *NameserverService) FindRecordByID(recID int) (*NameserverRecord, *NameserverDomain, error) { listResp, err := s.client.Nameservers.List("") if err != nil { return nil, nil, err } for _, domainItem := range listResp.Domains { resp, err := s.client.Nameservers.Info(&NameserverInfoRequest{RoID: domainItem.RoID}) if err != nil { return nil, nil, err } for _, record := range resp.Records { if record.ID == recID { return &record, &domainItem, nil } } } return nil, nil, fmt.Errorf("couldn't find INWX Record for id %d", recID) } // NameserverCheckResponse API model. type NameserverCheckResponse struct { Details []string Status string } // NameserverRecordRequest API model. type NameserverRecordRequest struct { RoID int `structs:"roId,omitempty"` Domain string `structs:"domain,omitempty"` Type string `structs:"type"` Content string `structs:"content"` Name string `structs:"name,omitempty"` TTL int `structs:"ttl,omitempty"` Priority int `structs:"prio,omitempty"` URLRedirectType string `structs:"urlRedirectType,omitempty"` URLRedirectTitle string `structs:"urlRedirectTitle,omitempty"` URLRedirectDescription string `structs:"urlRedirectDescription,omitempty"` URLRedirectFavIcon string `structs:"urlRedirectFavIcon,omitempty"` URLRedirectKeywords string `structs:"urlRedirectKeywords,omitempty"` } // NameserverCreateRequest API model. type NameserverCreateRequest struct { Domain string `structs:"domain"` Type string `structs:"type"` Nameservers []string `structs:"ns,omitempty"` MasterIP string `structs:"masterIp,omitempty"` Web string `structs:"web,omitempty"` Mail string `structs:"mail,omitempty"` SoaEmail string `structs:"soaEmail,omitempty"` URLRedirectType string `structs:"urlRedirectType,omitempty"` URLRedirectTitle string `structs:"urlRedirectTitle,omitempty"` URLRedirectDescription string `structs:"urlRedirectDescription,omitempty"` URLRedirectFavIcon string `structs:"urlRedirectFavIcon,omitempty"` URLRedirectKeywords string `structs:"urlRedirectKeywords,omitempty"` Testing bool `structs:"testing,omitempty"` } // NameserverInfoRequest API model. type NameserverInfoRequest struct { Domain string `structs:"domain,omitempty"` RoID int `structs:"roId,omitempty"` RecordID int `structs:"recordId,omitempty"` Type string `structs:"type,omitempty"` Name string `structs:"name,omitempty"` Content string `structs:"content,omitempty"` TTL int `structs:"ttl,omitempty"` Priority int `structs:"prio,omitempty"` } // NamserverInfoResponse API model. type NamserverInfoResponse struct { RoID int `mapstructure:"roId"` Domain string `mapstructure:"domain"` Type string `mapstructure:"type"` MasterIP string `mapstructure:"masterIp"` LastZoneCheck time.Time `mapstructure:"lastZoneCheck"` SlaveDNS []SlaveInfo `mapstructure:"slaveDns"` SOASerial string `mapstructure:"SOAserial"` Count int `mapstructure:"count"` Records []NameserverRecord `mapstructure:"record"` } // SlaveInfo API model. type SlaveInfo struct { Name string `mapstructure:"name"` IP string `mapstructure:"ip"` } // NameserverRecord API model. type NameserverRecord struct { ID int `mapstructure:"id"` Name string `mapstructure:"name"` Type string `mapstructure:"type"` Content string `mapstructure:"content"` TTL int `mapstructure:"TTL"` Priority int `mapstructure:"prio"` URLRedirectType string `mapstructure:"urlRedirectType"` URLRedirectTitle string `mapstructure:"urlRedirectTitle"` URLRedirectDescription string `mapstructure:"urlRedirectDescription"` URLRedirectKeywords string `mapstructure:"urlRedirectKeywords"` URLRedirectFavIcon string `mapstructure:"urlRedirectFavIcon"` } // NamserverListResponse API model. type NamserverListResponse struct { Count int Domains []NameserverDomain `mapstructure:"domains"` } // NameserverDomain API model. type NameserverDomain struct { RoID int `mapstructure:"roId"` Domain string `mapstructure:"domain"` Type string `mapstructure:"type"` MasterIP string `mapstructure:"masterIp"` Mail string `mapstructure:"mail"` Web string `mapstructure:"web"` URL string `mapstructure:"url"` Ipv4 string `mapstructure:"ipv4"` Ipv6 string `mapstructure:"ipv6"` } goinwx-0.8.1/response.go000066400000000000000000000015601371505770400152330ustar00rootroot00000000000000package goinwx import "fmt" // Response is a INWX API response. This wraps the standard http.Response returned from INWX. type Response struct { Code int `xmlrpc:"code"` Message string `xmlrpc:"msg"` ReasonCode string `xmlrpc:"reasonCode"` Reason string `xmlrpc:"reason"` ResponseData map[string]interface{} `xmlrpc:"resData"` } // An ErrorResponse reports the error caused by an API request. type ErrorResponse struct { Code int `xmlrpc:"code"` Message string `xmlrpc:"msg"` ReasonCode string `xmlrpc:"reasonCode"` Reason string `xmlrpc:"reason"` } func (r *ErrorResponse) Error() string { if r.Reason != "" { return fmt.Sprintf("(%d) %s. Reason: (%s) %s", r.Code, r.Message, r.ReasonCode, r.Reason) } return fmt.Sprintf("(%d) %s", r.Code, r.Message) }