initial commit

This commit is contained in:
ston1th 2017-01-13 00:05:57 +01:00
commit d1cfc3cc70
8 changed files with 383 additions and 0 deletions

24
LICENSE Normal file
View file

@ -0,0 +1,24 @@
Copyright (C) 2017 Marius Schellenberger
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
* The names of the authors and/or contributors may not be used to
endorse or promote products derived from this software without
specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL ston1th BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

9
README.md Normal file
View file

@ -0,0 +1,9 @@
# msrcgo - a simple API client and JSON decoder for the Microsoft Security Bulletins
For examples see: `cmd/main.go`
Or simply call it: `go run cmd/main.go <your api key>`
To get your API-Key, navigate here and log in with your microsoft account:
https://portal.msrc.microsoft.com/en-us/developer

23
cmd/curl_examples.sh Executable file
View file

@ -0,0 +1,23 @@
#!/bin/bash
key="<your api key>"
url="https://api.msrc.microsoft.com"
apiversion="?api-version=2016-08-01"
updates="/Updates"
#all updates
curl -H "api-key: ${key}" ${url}${updates}${apiversion}
#updates by id
id=2016-Sep
#id=CVE-1234-5678
#id=2016
curl -H "api-key: ${key}" "${url}${updates}('${id}')${apiversion}"
#by id
cvrfid=2017-Jan
#cvrfid=CVE-1234-5678
#cvrfid=2016
cvrf="/cvrf/"
curl -H "Accept: application/json" -H "api-key: ${key}" "${url}${cvrf}${cvrfid}${apiversion}"

19
cmd/main.go Normal file
View file

@ -0,0 +1,19 @@
package main
import (
"fmt"
"os"
"git.giftfish.de/ston1th/msrcgo"
)
func main() {
apikey := os.Args[1]
c := msrcgo.NewClient(apikey)
all, err := c.GetAllUpdates()
fmt.Println(all, err)
jan, err := c.GetUpdateID("2017-Jan")
fmt.Println(jan, err)
cvrf, err := c.GetCVRF("2017-Jan")
fmt.Println(cvrf, err)
}

3
doc.go Normal file
View file

@ -0,0 +1,3 @@
// Package msrcgo provides a simple API client and JSON decoder for the Microsoft Security Bulletins
package msrcgo

92
http.go Normal file
View file

@ -0,0 +1,92 @@
package msrcgo
import (
"errors"
"io"
"io/ioutil"
"net/http"
)
const (
APIVersion = "?api-version=2016-08-01"
UpdatesURI = "/Updates"
CvrfURI = "/cvrf/"
URL = "https://api.msrc.microsoft.com"
APIKeyHeader = "api-key"
AcceptHeader = "Accept"
AcceptValue = "application/json"
GET = "GET"
)
// Client represents the API client
type Client struct {
key string
allUpdates *http.Request
}
// NewClient returns a new Client instance
func NewClient(key string) *Client {
all, _ := http.NewRequest(GET, URL+UpdatesURI+APIVersion, nil)
all.Header.Set(AcceptHeader, AcceptValue)
all.Header.Set(APIKeyHeader, key)
return &Client{key, all}
}
// GetAllUpdates returns the Update struct (a list of all bulletins)
func (c *Client) GetAllUpdates() (*Update, error) {
return c.getUpdate(c.allUpdates)
}
// GetUpdateID returns a Update struct of the given id
// Example id: "2016-Sep"
func (c *Client) GetUpdateID(id string) (*Update, error) {
req, _ := http.NewRequest(GET, URL+UpdatesURI+"('"+id+"')"+APIVersion, nil)
req.Header.Set(AcceptHeader, AcceptValue)
req.Header.Set(APIKeyHeader, c.key)
return c.getUpdate(req)
}
// GetCVRF returns the CVRF struct of the given id
// Example id: "2016-Sep"
func (c *Client) GetCVRF(id string) (*CVRF, error) {
req, _ := http.NewRequest(GET, URL+CvrfURI+id+APIVersion, nil)
req.Header.Set(AcceptHeader, AcceptValue)
req.Header.Set(APIKeyHeader, c.key)
return c.getCVRF(req)
}
func (c *Client) request(req *http.Request) (body io.ReadCloser, err error) {
resp, err := (&http.Client{}).Do(req)
if err != nil {
return
}
if resp.StatusCode != http.StatusOK {
b, e := ioutil.ReadAll(resp.Body)
defer resp.Body.Close()
if e == nil {
err = errors.New(string(b))
}
return
}
body = resp.Body
return
}
func (c *Client) getUpdate(req *http.Request) (u *Update, err error) {
body, err := c.request(req)
if err != nil {
return
}
defer body.Close()
return DecodeUpdate(body)
}
func (c *Client) getCVRF(req *http.Request) (u *CVRF, err error) {
body, err := c.request(req)
if err != nil {
return
}
defer body.Close()
return DecodeCVRF(body)
}

127
json.go Normal file
View file

@ -0,0 +1,127 @@
package msrcgo
import (
"encoding/json"
"io"
"time"
)
// DecodeUpdate takes an io.Reader and returns the decoded Update struct
func DecodeUpdate(r io.Reader) (u *Update, err error) {
u = new(Update)
err = json.NewDecoder(r).Decode(u)
return
}
// Update represents the MSRC Updates
type Update struct {
OdataContext string `json:"@odata.context"`
Value []struct {
ID string `json:"ID"`
Alias string `json:"Alias"`
DocumentTitle string `json:"DocumentTitle"`
Severity interface{} `json:"Severity"`
InitialReleaseDate time.Time `json:"InitialReleaseDate"`
CurrentReleaseDate time.Time `json:"CurrentReleaseDate"`
CvrfURL string `json:"CvrfUrl"`
} `json:"value"`
}
// DecodeCVRF takes an io.Reader and returns the decoded CVRF struct
func DecodeCVRF(r io.Reader) (cvrf *CVRF, err error) {
cvrf = new(CVRF)
err = json.NewDecoder(r).Decode(cvrf)
return
}
// CVRF represents a single Security Bulletin
type CVRF struct {
DocumentTitle struct {
Value string `json:"Value"`
} `json:"DocumentTitle"`
DocumentType struct {
Value string `json:"Value"`
} `json:"DocumentType"`
DocumentPublisher struct {
ContactDetails struct {
Value string `json:"Value"`
} `json:"ContactDetails"`
IssuingAuthority struct {
Value string `json:"Value"`
} `json:"IssuingAuthority"`
Type int `json:"Type"`
} `json:"DocumentPublisher"`
DocumentTracking struct {
Identification struct {
ID struct {
Value string `json:"Value"`
} `json:"ID"`
Alias struct {
Value string `json:"Value"`
} `json:"Alias"`
} `json:"Identification"`
Status int `json:"Status"`
Version string `json:"Version"`
RevisionHistory []struct {
Number string `json:"Number"`
Date string `json:"Date"`
Description struct {
Value string `json:"Value"`
} `json:"Description"`
} `json:"RevisionHistory"`
InitialReleaseDate string `json:"InitialReleaseDate"`
CurrentReleaseDate string `json:"CurrentReleaseDate"`
} `json:"DocumentTracking"`
DocumentNotes []struct {
Title string `json:"Title"`
Audience string `json:"Audience"`
Type int `json:"Type"`
Ordinal string `json:"Ordinal"`
Value string `json:"Value"`
} `json:"DocumentNotes"`
ProductTree struct {
FullProductName []struct {
ProductID string `json:"ProductID"`
Value string `json:"Value"`
} `json:"FullProductName"`
} `json:"ProductTree"`
Vulnerability []struct {
Title struct {
Value string `json:"Value"`
} `json:"Title"`
Notes []struct {
Type int `json:"Type"`
Value string `json:"Value"`
} `json:"Notes"`
DiscoveryDateSpecified bool `json:"DiscoveryDateSpecified"`
ReleaseDateSpecified bool `json:"ReleaseDateSpecified"`
CVE string `json:"CVE"`
ProductStatuses []struct {
ProductID []string `json:"ProductID"`
Type int `json:"Type"`
} `json:"ProductStatuses"`
CVSSScoreSets []struct {
BaseScore float64 `json:"BaseScore"`
TemporalScore float64 `json:"TemporalScore"`
Vector string `json:"Vector"`
ProductID []string `json:"ProductID"`
} `json:"CVSSScoreSets"`
Remediations []struct {
Description struct {
Value string `json:"Value"`
} `json:"Description"`
URL string `json:"URL"`
ProductID []string `json:"ProductID"`
Type int `json:"Type"`
DateSpecified bool `json:"DateSpecified"`
AffectedFiles []interface{} `json:"AffectedFiles"`
} `json:"Remediations"`
Acknowledgments []struct {
Name []struct {
Value string `json:"Value"`
} `json:"Name"`
URL []string `json:"URL"`
} `json:"Acknowledgments"`
Ordinal string `json:"Ordinal"`
} `json:"Vulnerability"`
}

86
xml.go Normal file
View file

@ -0,0 +1,86 @@
package msrcgo
//NOTE XML is not yet supported
type xmlcvrf struct {
DocumentTitle string `xml:"DocumentTitle"`
DocumentType string `xml:"DocumentType"`
DocumentPublisher struct {
Type string `xml:"Type,attr"`
ContactDetails string `xml:"ContactDetails"`
IssuingAuthority string `xml:"IssuingAuthority"`
} `xml:"DocumentPublisher"`
DocumentTracking struct {
Identification struct {
ID string `xml:"ID"`
Alias string `xml"Alias"`
} `xml:"Identification"`
Status string `xml:"Status"`
Version string `xml:"Version"`
RevisionHistory struct {
Revision []struct {
Number int `xml:"Number"`
Date string `xml:"Date"`
Description string `xml:"Description"`
} `xml:"Revision"`
} `xml:"RevisionHistory"`
InitialReleaseDate string `xml:"InitialReleaseDate"`
CurrentReleaseDate string `xml:"CurrentReleaseDate"`
} `xml:"DocumentTracking"`
DocumentNotes struct {
Note []struct {
Title string `xml:"Title,attr"`
Audience string `xml:"Audience,attr"`
Type string `xml:"Type,attr"`
Ordinal string `xml:"Ordinal,attr"`
Note string `xml:",chardata"`
} `xml:"Note"`
} `xml:"DocumentNotes"`
ProductTree struct {
FullProductName []struct {
ProductID string `xml:"ProductID,attr"`
FullProductName string `xml:",chardata"`
} `xml:"FullProductName"`
} `xml:"ProductTree"`
Vulnerabilities []struct {
Ordinal string `xml:"Ordinal,attr"`
Title string `xml:"Title"`
Notes struct {
Note []struct {
Type string `xml:"Type,attr"`
Note string `xml:",chardata"`
} `xml:"Note"`
} `xml:"Notes"`
CVE string `xml:"CVE"`
ProductStatuses struct {
Status []struct {
Type string `xml:"Type,attr"`
ProductID string `xml:"ProductID"`
} `xml:"Status"`
} `xml:"ProductStatuses"`
CVSSScoreSets struct {
ScoreSet []struct {
BaseScore float32 `xml:"BaseScore"`
TemporalScore float32 `xml:"TemporalScore"`
Vector string `xml:"Vector"`
ProductID string `xml:"ProductID"`
} `xml:"ScoreSet"`
} `xml:"CVSSScoreSets"`
Remediations struct {
Remediation []struct {
Type string `xml:"Type,attr"`
Description string `xml:"Description"`
URL string `xml:"URL"`
ProductID string `xml:"ProductID"`
//NOTE not yet used
AffectedFields interface{} `xml:"AffectedFields"`
} `xml:"Remediation"`
} `xml:"Remediations"`
Acknowledgments struct {
Acknowledgment []struct {
Name string `xml:"Name"`
URL string `xml:"URL"`
} `json:Acknowledgment"`
} `xml:"Acknowledgments"`
} `xml:"Vulnerability"`
}