gocronometer

package module
v1.4.3 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 22, 2022 License: GPL-2.0 Imports: 14 Imported by: 1

README

gocronometer

gocronometer is an GPLv2 licensed Go module that provides a client for exporting data from Cronometer. It utilizes the export features to retrieve the CSV data from the unpublished API.

NOTE: This module utilizes the same API the SPA uses. For that reason it should only be used by single users wanting to export their personal data for backup or other reasons. It should never be used for integrations that the enterprise plan would cover. The library is licensed under the GPLv2 to help prevent the unacceptable usage.

Basic Example

// Create the client.
c := gocronometer.NewClient(nil)

// Login to cronometer.
err := c.Login(context.Background(), username, password)
if err != nil {
    t.Fatalf("failed to login with valid creds: %s", err)
}

// Retrieve the export data.
rawCSVData, err = c.ExportServings(context.Background(), time.Date(2020, 06, 01, 0, 0, 0, 0, time.UTC), time.Date(2020, 06, 04, 0, 0, 0, 0, time.UTC))
if err != nil {
    t.Fatalf("failed to retrieve servings: %s", err)
}

fmt.Println(rawCSVData)

Exports Supported

method description
ExportDailyNutrition() Exports daily nutrition information for the date range provided.
ExportServings() Exports servings for the date range provided.
ExportExercises() Exports exercises for the date range provided.
ExportBiometrics() Exports biometrics for the date range provided.
ExportNotes( Exports notes for the date range provided.

API Magic Values

This library mimics the GWT HTTP requests to perform the export of data. The GWT API exposed by Cronometer is not designed to be accessed from anything besides their deployed GWT application. For that reason, there are several values that can only be obtained from loading the application itself. These values change over time with application updates, and the library must use those new values.

The library includes the values as of the last push of the library. The new values can be provided to the client via the ClientOptions parameter of the NewClient function.

Magic Values
Name Location Changes
GWTContentType Retrieve from request header. false
GWTModuleBase Retrieve from request header. false
GWTPermutation Retrieve from request header. true
GWTHeader Retrieve from GWT request body. true

Documentation

Index

Constants

View Source
const (
	// HTMLLoginURL is the full URL to the Cronometer login page.
	HTMLLoginURL = "https://cronometer.com/login/"

	// APILoginURL is the full URL for login requests.
	APILoginURL = "https://cronometer.com/login"

	// GWTBaseURL is the full URL for accessing the GWT API.
	GWTBaseURL = "https://cronometer.com/cronometer/app"

	// APIExportURL is the full URL for requesting data exports.
	APIExportURL = "https://cronometer.com/export"
)
View Source
const (
	GWTContentType = "text/x-gwt-rpc; charset=UTF-8"
	GWTModuleBase  = "https://cronometer.com/cronometer/"
	GWTPermutation = "7B121DC5483BF272B1BC1916DA9FA963"

	// GWTHeader is what appears to be a hash value that is provided at the beginning of every GWT request. As it
	// changes with app updates it appears to be related to validating the version the requester is expecting.
	//GWTHeader = "3B6C5196158464C5643BA376AF05E7F1"
	GWTHeader = "2D6A926E3729946302DC68073CB0D550"
)

The following constants contain header values required for GWT requests. These values are found by inspecting a request from the web app. When the web app is updated these values can change. The values provided here are the default that will be used by the library if new values are not provided.

View Source
const (

	// GWTGenerateAuthToken will generate a GWT auth token. The only known use case is for accessing non GWT API calls
	// such as data export.
	// The first parameter in the string should be the sesnonce and the second is the users ID.
	GWTGenerateAuthToken = "7|0|8|https://cronometer.com/cronometer/|" + GWTHeader + "|com.cronometer.shared.rpc.CronometerService|generateAuthorizationToken" +
		"|java.lang.String/2004016611|I|com.cronometer.shared.user.AuthScope/2065601159|%s|1|2|3|4|4|5|6|6|7|8|%s|3600|7|2|"

	// GWTAuthenticate will authenticate with the GWT api. The sesnonce should be set in the cookies.
	GWTAuthenticate = "7|0|5|https://cronometer.com/cronometer/|" + GWTHeader + "|com.cronometer.shared.rpc.CronometerService|authenticate|java.lang.Integer/3438268394|1|2|3|4|1|5|5|-300|"

	// GWTLogout will log the session out.
	// The only parameter should be the sesnonce.
	GWTLogout = "7|0|6|https://cronometer.com/cronometer/|" + GWTHeader + "|com.cronometer.shared.rpc.CronometerService|logout|java.lang.String/2004016611|%s|1|2|3|4|1|5|6|"
)

The following are the GWT procedure calls as found from inspection of the app.

View Source
const GWTAuthRegex = `OK\[(?P<userid>\d*),.*`

Variables

View Source
var GWTAuthenticationRegexp = regexp.MustCompile(GWTAuthRegex)
View Source
var GWTTokenRegex = regexp.MustCompile("\"(?P<token>.*)\"")

Functions

This section is empty.

Types

type BiometricRecord added in v1.4.0

type BiometricRecord struct {
	RecordedTime time.Time
	Metric       string
	Unit         string
	Amount       float64
}

type BiometricRecords added in v1.4.0

type BiometricRecords []BiometricRecord

func ParseBiometricRecordsExport added in v1.4.0

func ParseBiometricRecordsExport(rawCSVReader io.Reader, location *time.Location) (BiometricRecords, error)

type Client

type Client struct {
	HTTPClient *http.Client
	Nonce      string
	UserID     string

	GWTContentType string
	GWTModuleBase  string
	GWTPermutation string
	GWTHeader      string
}

Client represents a client to the Cronometer API. The zero value is not a valid configuration. A new client should be generated with the NewClient function.

func NewClient

func NewClient(opts *ClientOptions) *Client

NewClient generates a new client for the Cronometer API. If opts is nil the default values are utilized.

func (*Client) ExportBiometricRecordsParsedWithLocation added in v1.4.0

func (c *Client) ExportBiometricRecordsParsedWithLocation(ctx context.Context, startDate time.Time, endDate time.Time, location *time.Location) (BiometricRecords, error)

ExportBiometricRecordsParsedWithLocation exports the biometric records within the date range and parses them into a go struct. Only the YYYY-mm-dd is utilized of startDate and endDate. The export is parsed and dates set to the location provided.

func (*Client) ExportBiometrics

func (c *Client) ExportBiometrics(ctx context.Context, startDate time.Time, endDate time.Time) (string, error)

ExportBiometrics exports the biometrics within the date range. Only the YYYY-mm-dd is utilized of startDate and endDate. The export is the raw string data.

func (*Client) ExportDailyNutrition

func (c *Client) ExportDailyNutrition(ctx context.Context, startDate time.Time, endDate time.Time) (string, error)

ExportDailyNutrition exports the daily nutrition values within the date range. Only the YYYY-mm-dd is utilized of startDate and endDate. The export is the raw string data.

func (*Client) ExportExercises

func (c *Client) ExportExercises(ctx context.Context, startDate time.Time, endDate time.Time) (string, error)

ExportExercises exports the exercises within the date range. Only the YYYY-mm-dd is utilized of startDate and endDate. The export is the raw string data.

func (*Client) ExportExercisesParsedWithLocation added in v1.3.0

func (c *Client) ExportExercisesParsedWithLocation(ctx context.Context, startDate time.Time, endDate time.Time, location *time.Location) (ExerciseRecords, error)

ExportExercisesParsedWithLocation exports the exercises within the date range and parses them into a go struct. Only the YYYY-mm-dd is utilized of startDate and endDate. The export is parsed and dates set to the location provided.

func (*Client) ExportNotes

func (c *Client) ExportNotes(ctx context.Context, startDate time.Time, endDate time.Time) (string, error)

ExportNotes exports the notes within the date range. Only the YYYY-mm-dd is utilized of startDate and endDate. The export is the raw string data.

func (*Client) ExportServings

func (c *Client) ExportServings(ctx context.Context, startDate time.Time, endDate time.Time) (string, error)

ExportServings exports all the services within the date range. Only the YYYY-mm-dd is utilized of startDate and endDate. The export is the raw string data.

func (*Client) ExportServingsParsed added in v1.1.0

func (c *Client) ExportServingsParsed(ctx context.Context, startDate time.Time, endDate time.Time) (ServingRecords, error)

ExportServingsParsed exports the servings within the date range and parses them into a go struct. Only the YYYY-mm-dd is utilized of startDate and endDate. The export is the raw string data.

func (*Client) ExportServingsParsedWithLocation added in v1.2.0

func (c *Client) ExportServingsParsedWithLocation(ctx context.Context, startDate time.Time, endDate time.Time, location *time.Location) (ServingRecords, error)

ExportServingsParsedWithLocation is the same as ExportServingsParsed but sets the location of every recorded time to the location provided.

func (*Client) GWTAuthenticate

func (c *Client) GWTAuthenticate(ctx context.Context) error

GWTAuthenticate will authenticate with the GWT API using the sesnonce of the client. Login() calls this by default so in most cases this should never be called directly.

func (*Client) GenerateAuthToken

func (c *Client) GenerateAuthToken(ctx context.Context) (string, error)

GenerateAuthToken requests an authentication token from the API. This token is used to request the generation of a "token" that is provided as a nonce to the export API calls.

func (*Client) Login

func (c *Client) Login(ctx context.Context, username string, password string) error

Login logs into the Cronometer and the GWT API. Nil is returned on login success.

func (*Client) Logout

func (c *Client) Logout(ctx context.Context) error

Logout logs out from the API.

func (*Client) NewExportRequest

func (c *Client) NewExportRequest(ctx context.Context, method string, url string, body io.Reader) (*http.Request, error)

NewExportRequest creates a new http request for exports.

func (*Client) NewGWTRequestWithContext

func (c *Client) NewGWTRequestWithContext(ctx context.Context, method string, url string, body io.Reader) (*http.Request, error)

NewGWTRequestWithContext creates a new http request with the proper headers for a GWT request.

func (*Client) ObtainAntiCSRF

func (c *Client) ObtainAntiCSRF(ctx context.Context) (string, error)

ObtainAntiCSRF connects to the login page of Cronometer and parses out the anticsrf value from the HTML form.

type ClientOptions

type ClientOptions struct {
	GWTContentType string
	GWTModuleBase  string
	GWTPermutation string
	GWTHeader      string
}

ClientOptions represents the options that can be provided to the client. Zero values revert to the library defaults.

type ExerciseRecord added in v1.3.0

type ExerciseRecord struct {
	RecordedTime   time.Time
	Exercise       string
	Minutes        float64
	CaloriesBurned float64
}

type ExerciseRecords added in v1.3.0

type ExerciseRecords []ExerciseRecord

func ParseExerciseExport added in v1.4.0

func ParseExerciseExport(rawCSVReader io.Reader, location *time.Location) (ExerciseRecords, error)

type LoginResponse

type LoginResponse struct {
	Redirect string `json:"redirect"`
	Success  bool   `json:"success"`
	Error    string `json:"error"`
}

type ServingRecord added in v1.1.0

type ServingRecord struct {
	RecordedTime     time.Time
	Group            string
	FoodName         string
	QuantityValue    float64
	QuantityUnits    string
	EnergyKcal       float64
	CaffeineMg       float64
	WaterG           float64
	B1Mg             float64
	B2Mg             float64
	B3Mg             float64
	B5Mg             float64
	B6Mg             float64
	B12Mg            float64
	BiotinUg         float64
	CholineMg        float64
	FolateUg         float64
	VitaminAUI       float64
	VitaminCMg       float64
	VitaminDUI       float64
	VitaminEMg       float64
	VitaminKMg       float64
	CalciumMg        float64
	ChromiumUg       float64
	CopperMg         float64
	FluorideUg       float64
	IodineUg         float64
	MagnesiumMg      float64
	ManganeseMg      float64
	PhosphorusMg     float64
	PotassiumMg      float64
	SeleniumUg       float64
	SodiumMg         float64
	ZincMg           float64
	CarbsG           float64
	FiberG           float64
	FructoseG        float64
	GalactoseG       float64
	GlucoseG         float64
	LactoseG         float64
	MaltoseG         float64
	StarchG          float64
	SucroseG         float64
	SugarsG          float64
	NetCarbsG        float64
	FatG             float64
	CholesterolMg    float64
	MonounsaturatedG float64
	PolyunsaturatedG float64
	SaturatedG       float64
	TransFatG        float64
	Omega3G          float64
	Omega6G          float64
	CystineG         float64
	HistidineG       float64
	IsoleucineG      float64
	LeucineG         float64
	LysineG          float64
	MethionineG      float64
	PhenylalanineG   float64
	ThreonineG       float64
	TryptophanG      float64
	TyrosineG        float64
	ValineG          float64
	ProtienG         float64
	IronMg           float64
	Category         string
}

type ServingRecords added in v1.1.0

type ServingRecords []ServingRecord

func ParseServingsExport added in v1.1.0

func ParseServingsExport(rawCSVReader io.Reader, location *time.Location) (ServingRecords, error)

type ServingsExport added in v1.1.0

type ServingsExport struct {
	Records ServingRecords
}

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL