ofx died 3y ago
This commit is contained in:
206
vendor/github.com/aclindsa/ofxgo/profile.go
generated
vendored
Normal file
206
vendor/github.com/aclindsa/ofxgo/profile.go
generated
vendored
Normal file
@@ -0,0 +1,206 @@
|
||||
package ofxgo
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"github.com/aclindsa/xml"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// ProfileRequest represents a request for a server to provide a profile of its
|
||||
// capabilities (which message sets and versions it supports, how to access
|
||||
// them, which languages and which types of synchronization they support, etc.)
|
||||
type ProfileRequest struct {
|
||||
XMLName xml.Name `xml:"PROFTRNRQ"`
|
||||
TrnUID UID `xml:"TRNUID"`
|
||||
CltCookie String `xml:"CLTCOOKIE,omitempty"`
|
||||
TAN String `xml:"TAN,omitempty"` // Transaction authorization number
|
||||
// TODO `xml:"OFXEXTENSION,omitempty"`
|
||||
ClientRouting String `xml:"PROFRQ>CLIENTROUTING"` // Forced to NONE
|
||||
DtProfUp Date `xml:"PROFRQ>DTPROFUP"` // Date and time client last received a profile update
|
||||
}
|
||||
|
||||
// Name returns the name of the top-level transaction XML/SGML element
|
||||
func (r *ProfileRequest) Name() string {
|
||||
return "PROFTRNRQ"
|
||||
}
|
||||
|
||||
// Valid returns (true, nil) if this struct would be valid OFX if marshalled
|
||||
// into XML/SGML
|
||||
func (r *ProfileRequest) Valid(version ofxVersion) (bool, error) {
|
||||
if ok, err := r.TrnUID.Valid(); !ok {
|
||||
return false, err
|
||||
}
|
||||
// TODO implement
|
||||
r.ClientRouting = "NONE"
|
||||
return true, nil
|
||||
}
|
||||
|
||||
// Type returns which message set this message belongs to (which Request
|
||||
// element of type []Message it should appended to)
|
||||
func (r *ProfileRequest) Type() messageType {
|
||||
return ProfRq
|
||||
}
|
||||
|
||||
// SignonInfo provides the requirements to login to a single signon realm. A
|
||||
// signon realm consists of all MessageSets which can be accessed using one set
|
||||
// of login credentials. Most FI's only use one signon realm to make it easier
|
||||
// and less confusing for the user.
|
||||
type SignonInfo struct {
|
||||
XMLName xml.Name `xml:"SIGNONINFO"`
|
||||
SignonRealm String `xml:"SIGNONREALM"` // The SignonRealm for which this SignonInfo provides information. This SignonInfo is valid for all MessageSets with SignonRealm fields matching this one
|
||||
Min Int `xml:"MIN"` // Minimum number of password characters
|
||||
Max Int `xml:"MAX"` // Maximum number of password characters
|
||||
CharType charType `xml:"CHARTYPE"` // One of ALPHAONLY, NUMERICONLY, ALPHAORNUMERIC, ALPHAANDNUMERIC
|
||||
CaseSen Boolean `xml:"CASESEN"` // Password is case-sensitive?
|
||||
Special Boolean `xml:"SPECIAL"` // Special characters allowed?
|
||||
Spaces Boolean `xml:"SPACES"` // Spaces allowed?
|
||||
PinCh Boolean `xml:"PINCH"` // Pin change <PINCHRQ> requests allowed
|
||||
ChgPinFirst Boolean `xml:"CHGPINFIRST"` // Server requires user to change password at first signon
|
||||
UserCred1Label String `xml:"USERCRED1LABEL,omitempty"` // Prompt for USERCRED1 (if this field is present, USERCRED1 is required)
|
||||
UserCred2Label String `xml:"USERCRED2LABEL,omitempty"` // Prompt for USERCRED2 (if this field is present, USERCRED2 is required)
|
||||
ClientUIDReq Boolean `xml:"CLIENTUIDREQ,omitempty"` // CLIENTUID required?
|
||||
AuthTokenFirst Boolean `xml:"AUTHTOKENFIRST,omitempty"` // Server requires AUTHTOKEN as part of first signon
|
||||
AuthTokenLabel String `xml:"AUTHTOKENLABEL,omitempty"`
|
||||
AuthTokenInfoURL String `xml:"AUTHTOKENINFOURL,omitempty"`
|
||||
MFAChallengeSupt Boolean `xml:"MFACHALLENGESUPT,omitempty"` // Server supports MFACHALLENGE
|
||||
MFAChallengeFIRST Boolean `xml:"MFACHALLENGEFIRST,omitempty"` // Server requires MFACHALLENGE to be sent with first signon
|
||||
AccessTokenReq Boolean `xml:"ACCESSTOKENREQ,omitempty"` // Server requires ACCESSTOKEN to be sent with all requests except profile
|
||||
}
|
||||
|
||||
// MessageSet represents one message set supported by an FI and its
|
||||
// capabilities
|
||||
type MessageSet struct {
|
||||
XMLName xml.Name // <xxxMSGSETVn>
|
||||
Name string // <xxxMSGSETVn> (copy of XMLName.Local)
|
||||
Ver Int `xml:"MSGSETCORE>VER"` // Message set version - should always match 'n' in <xxxMSGSETVn> of Name
|
||||
URL String `xml:"MSGSETCORE>URL"` // URL where messages in this set are to be set
|
||||
OfxSec ofxSec `xml:"MSGSETCORE>OFXSEC"` // NONE or 'TYPE 1'
|
||||
TranspSec Boolean `xml:"MSGSETCORE>TRANSPSEC"` // Transport-level security must be used
|
||||
SignonRealm String `xml:"MSGSETCORE>SIGNONREALM"` // Used to identify which SignonInfo to use for to this MessageSet
|
||||
Language []String `xml:"MSGSETCORE>LANGUAGE"` // List of supported languages
|
||||
SyncMode syncMode `xml:"MSGSETCORE>SYNCMODE"` // One of FULL, LITE
|
||||
RefreshSupt Boolean `xml:"MSGSETCORE>REFRESHSUPT,omitempty"` // Y if server supports <REFRESH>Y within synchronizations. This option is irrelevant for full synchronization servers. Clients must ignore <REFRESHSUPT> (or its absence) if the profile also specifies <SYNCMODE>FULL. For lite synchronization, the default is N. Without <REFRESHSUPT>Y, lite synchronization servers are not required to support <REFRESH>Y requests
|
||||
RespFileER Boolean `xml:"MSGSETCORE>RESPFILEER"` // server supports file-based error recovery
|
||||
SpName String `xml:"MSGSETCORE>SPNAME"` // Name of service provider
|
||||
// TODO MessageSet-specific stuff?
|
||||
}
|
||||
|
||||
// MessageSetList is a list of MessageSets (necessary because they must be
|
||||
// manually parsed)
|
||||
type MessageSetList []MessageSet
|
||||
|
||||
// UnmarshalXML handles unmarshalling a MessageSetList element from an XML string
|
||||
func (msl *MessageSetList) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error {
|
||||
for {
|
||||
var msgset MessageSet
|
||||
tok, err := nextNonWhitespaceToken(d)
|
||||
if err != nil {
|
||||
return err
|
||||
} else if end, ok := tok.(xml.EndElement); ok && end.Name.Local == start.Name.Local {
|
||||
// If we found the end of our starting element, we're done parsing
|
||||
return nil
|
||||
} else if _, ok := tok.(xml.StartElement); ok {
|
||||
// Found starting tag for <xxxMSGSET>. Get the next one (xxxMSGSETVn) and decode that struct
|
||||
tok, err := nextNonWhitespaceToken(d)
|
||||
if err != nil {
|
||||
return err
|
||||
} else if versionStart, ok := tok.(xml.StartElement); ok {
|
||||
if err := d.DecodeElement(&msgset, &versionStart); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
return errors.New("Invalid MSGSETLIST formatting")
|
||||
}
|
||||
msgset.Name = msgset.XMLName.Local
|
||||
|
||||
// Eat ending tags for <xxxMSGSET>
|
||||
tok, err = nextNonWhitespaceToken(d)
|
||||
if err != nil {
|
||||
return err
|
||||
} else if _, ok := tok.(xml.EndElement); !ok {
|
||||
return errors.New("Invalid MSGSETLIST formatting")
|
||||
}
|
||||
} else {
|
||||
return errors.New("MSGSETLIST didn't find an opening xxxMSGSETVn element")
|
||||
}
|
||||
*msl = MessageSetList(append(*(*[]MessageSet)(msl), msgset))
|
||||
}
|
||||
}
|
||||
|
||||
// MarshalXML handles marshalling a MessageSetList element to an XML string
|
||||
func (msl *MessageSetList) MarshalXML(e *xml.Encoder, start xml.StartElement) error {
|
||||
messageSetListElement := xml.StartElement{Name: xml.Name{Local: "MSGSETLIST"}}
|
||||
if err := e.EncodeToken(messageSetListElement); err != nil {
|
||||
return err
|
||||
}
|
||||
for _, messageset := range *msl {
|
||||
if !strings.HasSuffix(messageset.Name, "V1") {
|
||||
return errors.New("Expected MessageSet.Name to end with \"V1\"")
|
||||
}
|
||||
messageSetName := strings.TrimSuffix(messageset.Name, "V1")
|
||||
messageSetElement := xml.StartElement{Name: xml.Name{Local: messageSetName}}
|
||||
if err := e.EncodeToken(messageSetElement); err != nil {
|
||||
return err
|
||||
}
|
||||
start := xml.StartElement{Name: xml.Name{Local: messageset.Name}}
|
||||
if err := e.EncodeElement(&messageset, start); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := e.EncodeToken(messageSetElement.End()); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if err := e.EncodeToken(messageSetListElement.End()); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// ProfileResponse contains a requested profile of the server's capabilities
|
||||
// (which message sets and versions it supports, how to access them, which
|
||||
// languages and which types of synchronization they support, etc.). Note that
|
||||
// if the server does not support ClientRouting=NONE (as we always send with
|
||||
// ProfileRequest), this may be an error)
|
||||
type ProfileResponse struct {
|
||||
XMLName xml.Name `xml:"PROFTRNRS"`
|
||||
TrnUID UID `xml:"TRNUID"`
|
||||
Status Status `xml:"STATUS"`
|
||||
CltCookie String `xml:"CLTCOOKIE,omitempty"`
|
||||
// TODO `xml:"OFXEXTENSION,omitempty"`
|
||||
MessageSetList MessageSetList `xml:"PROFRS>MSGSETLIST"`
|
||||
SignonInfoList []SignonInfo `xml:"PROFRS>SIGNONINFOLIST>SIGNONINFO"`
|
||||
DtProfUp Date `xml:"PROFRS>DTPROFUP"`
|
||||
FiName String `xml:"PROFRS>FINAME"`
|
||||
Addr1 String `xml:"PROFRS>ADDR1"`
|
||||
Addr2 String `xml:"PROFRS>ADDR2,omitempty"`
|
||||
Addr3 String `xml:"PROFRS>ADDR3,omitempty"`
|
||||
City String `xml:"PROFRS>CITY"`
|
||||
State String `xml:"PROFRS>STATE"`
|
||||
PostalCode String `xml:"PROFRS>POSTALCODE"`
|
||||
Country String `xml:"PROFRS>COUNTRY"`
|
||||
CsPhone String `xml:"PROFRS>CSPHONE,omitempty"`
|
||||
TsPhone String `xml:"PROFRS>TSPHONE,omitempty"`
|
||||
FaxPhone String `xml:"PROFRS>FAXPHONE,omitempty"`
|
||||
URL String `xml:"PROFRS>URL,omitempty"`
|
||||
Email String `xml:"PROFRS>EMAIL,omitempty"`
|
||||
}
|
||||
|
||||
// Name returns the name of the top-level transaction XML/SGML element
|
||||
func (pr *ProfileResponse) Name() string {
|
||||
return "PROFTRNRS"
|
||||
}
|
||||
|
||||
// Valid returns (true, nil) if this struct was valid OFX when unmarshalled
|
||||
func (pr *ProfileResponse) Valid(version ofxVersion) (bool, error) {
|
||||
if ok, err := pr.TrnUID.Valid(); !ok {
|
||||
return false, err
|
||||
}
|
||||
//TODO implement
|
||||
return true, nil
|
||||
}
|
||||
|
||||
// Type returns which message set this message belongs to (which Response
|
||||
// element of type []Message it belongs to)
|
||||
func (pr *ProfileResponse) Type() messageType {
|
||||
return ProfRs
|
||||
}
|
||||
Reference in New Issue
Block a user