~rockorager/go-jmap

821d0924a12e627350a2e662210f2e08e26e271e — Robin Jarry 9 months ago 66a3389 v0.4.2
dates: force UTC timezone

In the RFC, it is stated that all (or almost all) dates should be
"UTCDate" (e.g. in the UTC timezone and formatted with a trailing "Z").

Convert the dates to use the UTC timezone when required before
marshaling to JSON. Create type aliases to be able to call
json.Marshal() from MarshalJSON() without a recursion error.

Link: https://www.rfc-editor.org/rfc/rfc8620.html#section-1.4
Link: https://www.rfc-editor.org/rfc/rfc8621.html#section-4.4.1
Link: https://choly.ca/post/go-json-marshalling/
Signed-off-by: Robin Jarry <robin@jarry.cc>
M mail/email/filter.go => mail/email/filter.go +15 -0
@@ 1,6 1,7 @@
package email

import (
	"encoding/json"
	"time"

	"git.sr.ht/~rockorager/go-jmap"


@@ 127,3 128,17 @@ type FilterCondition struct {
}

func (fc *FilterCondition) implementsFilter() {}

func (fc *FilterCondition) MarshalJSON() ([]byte, error) {
	if fc.Before != nil && fc.Before.Location() != time.UTC {
		utc := fc.Before.UTC()
		fc.Before = &utc
	}
	if fc.After != nil && fc.After.Location() != time.UTC {
		utc := fc.After.UTC()
		fc.After = &utc
	}
	// create a type alias to avoid infinite recursion
	type Alias FilterCondition
	return json.Marshal((*Alias)(fc))
}

M mail/emailsubmission/emailsubmission.go => mail/emailsubmission/emailsubmission.go +10 -0
@@ 89,6 89,16 @@ type EmailSubmission struct {
	MDNBlobIDs []jmap.ID `json:"mdnBlobIds,omitempty"`
}

func (s *EmailSubmission) MarshalJSON() ([]byte, error) {
	if s.SendAt != nil && s.SendAt.Location() != time.UTC {
		utc := s.SendAt.UTC()
		s.SendAt = &utc
	}
	// create a type alias to avoid infinite recursion
	type Alias EmailSubmission
	return json.Marshal((*Alias)(s))
}

type Envelope struct {
	// The email address to use as the return address in the SMTP submission
	MailFrom *Address `json:"mailfrom,omitempty"`

M mail/emailsubmission/filter.go => mail/emailsubmission/filter.go +15 -0
@@ 1,6 1,7 @@
package emailsubmission

import (
	"encoding/json"
	"time"

	"git.sr.ht/~rockorager/go-jmap"


@@ 48,3 49,17 @@ type FilterCondition struct {
}

func (fc *FilterCondition) implementsFilter() {}

func (fc *FilterCondition) MarshalJSON() ([]byte, error) {
	if fc.Before != nil && fc.Before.Location() != time.UTC {
		utc := fc.Before.UTC()
		fc.Before = &utc
	}
	if fc.After != nil && fc.After.Location() != time.UTC {
		utc := fc.After.UTC()
		fc.After = &utc
	}
	// create a type alias to avoid infinite recursion
	type Alias FilterCondition
	return json.Marshal((*Alias)(fc))
}

M mail/vacationresponse/vacationresponse.go => mail/vacationresponse/vacationresponse.go +13 -0
@@ 1,6 1,7 @@
package vacationresponse

import (
	"encoding/json"
	"time"

	"git.sr.ht/~rockorager/go-jmap"


@@ 49,3 50,15 @@ type VacationResponse struct {
	// The HTML body to send in the response
	HTMLBody *string `json:"htmlBody,omitempty"`
}

func (v *VacationResponse) MarshalJson() ([]byte, error) {
	if v.FromDate != nil && v.FromDate.Location() != time.UTC {
		utc := v.FromDate.UTC()
		v.FromDate = &utc
	}
	if v.ToDate != nil && v.ToDate.Location() != time.UTC {
		utc := v.ToDate.UTC()
		v.ToDate = &utc
	}
	return json.Marshal(v)
}