github.com/choria-io/go-choria@v0.28.1-0.20240416190746-b3bf9c7d5a45/choria/protocol.go (about) 1 // Copyright (c) 2017-2022, R.I. Pienaar and the Choria Project contributors 2 // 3 // SPDX-License-Identifier: Apache-2.0 4 5 package choria 6 7 import ( 8 "context" 9 "fmt" 10 11 "github.com/choria-io/go-choria/inter" 12 "github.com/choria-io/go-choria/message" 13 "github.com/choria-io/go-choria/protocol" 14 v1 "github.com/choria-io/go-choria/protocol/v1" 15 v2 "github.com/choria-io/go-choria/protocol/v2" 16 ) 17 18 // NewMessage creates a new Message associated with this Choria instance 19 func (fw *Framework) NewMessage(payload []byte, agent string, collective string, msgType string, request inter.Message) (msg inter.Message, err error) { 20 return message.NewMessage(payload, agent, collective, msgType, request, fw) 21 } 22 23 // RequestProtocol determines the protocol version to use based on security provider technology 24 func (fw *Framework) RequestProtocol() protocol.ProtocolVersion { 25 switch fw.security.BackingTechnology() { 26 case inter.SecurityTechnologyX509: 27 return protocol.RequestV1 28 29 case inter.SecurityTechnologyED25519JWT: 30 return protocol.RequestV2 31 32 default: 33 return protocol.Unknown 34 } 35 } 36 37 // NewRequestMessageFromTransportJSON creates a Message from a Transport JSON that holds a Request 38 func (fw *Framework) NewRequestMessageFromTransportJSON(payload []byte) (inter.Message, error) { 39 transport, err := fw.NewTransportFromJSON(payload) 40 if err != nil { 41 return nil, err 42 } 43 44 srequest, err := fw.NewSecureRequestFromTransport(transport, false) 45 if err != nil { 46 return nil, err 47 } 48 49 request, err := fw.NewRequestFromSecureRequest(srequest) 50 if err != nil { 51 return nil, err 52 } 53 54 protocol.CopyFederationData(transport, request) 55 56 msg, err := message.NewMessageFromRequest(request, transport.ReplyTo(), fw) 57 if err != nil { 58 return nil, err 59 } 60 61 return msg, nil 62 } 63 64 func (fw *Framework) NewMessageFromRequest(req protocol.Request, replyto string) (inter.Message, error) { 65 return message.NewMessageFromRequest(req, replyto, fw) 66 } 67 68 // NewReplyFromTransportJSON creates a new Reply from a transport JSON 69 func (fw *Framework) NewReplyFromTransportJSON(payload []byte, skipvalidate bool) (msg protocol.Reply, err error) { 70 transport, err := fw.NewTransportFromJSON(payload) 71 if err != nil { 72 return nil, err 73 } 74 75 sreply, err := fw.NewSecureReplyFromTransport(transport, skipvalidate) 76 if err != nil { 77 return nil, err 78 } 79 80 reply, err := fw.NewReplyFromSecureReply(sreply) 81 if err != nil { 82 return nil, err 83 } 84 85 protocol.CopyFederationData(transport, reply) 86 87 return reply, nil 88 } 89 90 // NewRequestFromTransportJSON creates a new Request from transport JSON 91 func (fw *Framework) NewRequestFromTransportJSON(payload []byte, skipvalidate bool) (msg protocol.Request, err error) { 92 transport, err := fw.NewTransportFromJSON(payload) 93 if err != nil { 94 return nil, err 95 } 96 97 sreq, err := fw.NewSecureRequestFromTransport(transport, skipvalidate) 98 if err != nil { 99 return nil, err 100 } 101 102 req, err := fw.NewRequestFromSecureRequest(sreq) 103 if err != nil { 104 return nil, err 105 } 106 107 protocol.CopyFederationData(transport, req) 108 109 return req, nil 110 } 111 112 // NewRequest creates a new Request complying with a specific protocol version like protocol.RequestV1 113 func (fw *Framework) NewRequest(version protocol.ProtocolVersion, agent string, senderid string, callerid string, ttl int, requestid string, collective string) (request protocol.Request, err error) { 114 switch version { 115 case protocol.RequestV1: 116 request, err = v1.NewRequest(agent, senderid, callerid, ttl, requestid, collective) 117 case protocol.RequestV2: 118 request, err = v2.NewRequest(agent, senderid, callerid, ttl, requestid, collective) 119 default: 120 err = fmt.Errorf("do not know how to create a Request version %s", version) 121 } 122 123 return request, err 124 } 125 126 // NewRequestFromMessage creates a new Request with the Message settings preloaded complying with a specific protocol version like protocol.RequestV1 127 func (fw *Framework) NewRequestFromMessage(version protocol.ProtocolVersion, msg inter.Message) (req protocol.Request, err error) { 128 if !(msg.Type() == inter.RequestMessageType || msg.Type() == inter.DirectRequestMessageType || msg.Type() == inter.ServiceRequestMessageType) { 129 err = fmt.Errorf("cannot use '%s' message to construct a Request", msg.Type()) 130 return nil, err 131 } 132 133 req, err = fw.NewRequest(version, msg.Agent(), msg.SenderID(), msg.CallerID(), msg.TTL(), msg.RequestID(), msg.Collective()) 134 if err != nil { 135 return nil, fmt.Errorf("could not create a Request from a Message: %s", err) 136 } 137 138 req.SetMessage(msg.Payload()) 139 140 if msg.Filter() == nil { 141 req.NewFilter() 142 } else { 143 req.SetFilter(msg.Filter()) 144 } 145 146 return req, nil 147 } 148 149 // NewReply creates a new Reply, the version will match that of the given request 150 func (fw *Framework) NewReply(request protocol.Request) (reply protocol.Reply, err error) { 151 switch request.Version() { 152 case protocol.RequestV1: 153 return v1.NewReply(request, fw.Config.Identity) 154 case protocol.RequestV2: 155 return v2.NewReply(request, fw.Config.Identity) 156 default: 157 return nil, fmt.Errorf("do not know how to create a Reply version %s", request.Version()) 158 } 159 } 160 161 // NewReplyFromMessage creates a new Reply with the Message settings preloaded complying with a specific protocol version like protocol.ReplyV1 162 func (fw *Framework) NewReplyFromMessage(version protocol.ProtocolVersion, msg inter.Message) (rep protocol.Reply, err error) { 163 if msg.Type() != "reply" { 164 return nil, fmt.Errorf("cannot use '%s' message to construct a Reply", msg.Type()) 165 } 166 167 if msg.Request() == nil { 168 return nil, fmt.Errorf("cannot create a Reply from Messages without Requests") 169 } 170 171 req, err := fw.NewRequestFromMessage(version, msg.Request()) 172 if err != nil { 173 return nil, err 174 } 175 176 rep, err = fw.NewReply(req) 177 rep.SetMessage(msg.Payload()) 178 179 return rep, err 180 } 181 182 // NewReplyFromSecureReply creates a new Reply from the JSON payload of SecureReply, the version will match what is in the JSON payload 183 func (fw *Framework) NewReplyFromSecureReply(sr protocol.SecureReply) (reply protocol.Reply, err error) { 184 switch sr.Version() { 185 case protocol.SecureReplyV1: 186 return v1.NewReplyFromSecureReply(sr) 187 case protocol.SecureReplyV2: 188 return v2.NewReplyFromSecureReply(sr) 189 default: 190 return nil, fmt.Errorf("do not know how to create a Reply version %s", sr.Version()) 191 } 192 } 193 194 // NewRequestFromSecureRequest creates a new Request from a SecureRequest, the version will match what is in the JSON payload 195 func (fw *Framework) NewRequestFromSecureRequest(sr protocol.SecureRequest) (request protocol.Request, err error) { 196 switch sr.Version() { 197 case protocol.SecureRequestV1: 198 return v1.NewRequestFromSecureRequest(sr) 199 case protocol.SecureRequestV2: 200 return v2.NewRequestFromSecureRequest(sr) 201 default: 202 return nil, fmt.Errorf("do not know how to create a Reply version %s", sr.Version()) 203 } 204 205 } 206 207 // NewSecureReply creates a new SecureReply with the given Reply message as payload 208 func (fw *Framework) NewSecureReply(reply protocol.Reply) (secure protocol.SecureReply, err error) { 209 switch reply.Version() { 210 case protocol.ReplyV1: 211 return v1.NewSecureReply(reply, fw.security) 212 case protocol.ReplyV2: 213 return v2.NewSecureReply(reply, fw.security) 214 default: 215 return nil, fmt.Errorf("do not know how to create a SecureReply based on a Reply version %s", reply.Version()) 216 } 217 218 } 219 220 // NewSecureReplyFromTransport creates a new SecureReply from the JSON payload of TransportMessage, the version SecureReply will be the same as the TransportMessage 221 func (fw *Framework) NewSecureReplyFromTransport(message protocol.TransportMessage, skipvalidate bool) (secure protocol.SecureReply, err error) { 222 switch message.Version() { 223 case protocol.TransportV1: 224 return v1.NewSecureReplyFromTransport(message, fw.security, skipvalidate) 225 case protocol.TransportV2: 226 return v2.NewSecureReplyFromTransport(message, fw.security, skipvalidate) 227 default: 228 return nil, fmt.Errorf("do not know how to create a SecureReply version %s", message.Version()) 229 } 230 } 231 232 // NewSecureRequest creates a new SecureRequest with the given Request message as payload 233 func (fw *Framework) NewSecureRequest(ctx context.Context, request protocol.Request) (secure protocol.SecureRequest, err error) { 234 switch request.Version() { 235 case protocol.RequestV1: 236 if fw.security.IsRemoteSigning() { 237 return v1.NewRemoteSignedSecureRequest(ctx, request, fw.security) 238 } 239 240 return v1.NewSecureRequest(request, fw.security) 241 case protocol.RequestV2: 242 if fw.security.IsRemoteSigning() { 243 return v2.NewRemoteSignedSecureRequest(ctx, request, fw.security) 244 } 245 246 return v2.NewSecureRequest(request, fw.security) 247 default: 248 return nil, fmt.Errorf("do not know how to create a SecureReply from a Request with version %s", request.Version()) 249 } 250 } 251 252 // NewSecureRequestFromTransport creates a new SecureRequest from the JSON payload of TransportMessage, the version SecureRequest will be the same as the TransportMessage 253 func (fw *Framework) NewSecureRequestFromTransport(message protocol.TransportMessage, skipvalidate bool) (secure protocol.SecureRequest, err error) { 254 switch message.Version() { 255 case protocol.TransportV1: 256 return v1.NewSecureRequestFromTransport(message, fw.security, skipvalidate) 257 case protocol.TransportV2: 258 return v2.NewSecureRequestFromTransport(message, fw.security, skipvalidate) 259 default: 260 return nil, fmt.Errorf("do not know how to create a SecureReply from a TransportMessage version %s", message.Version()) 261 } 262 } 263 264 // NewTransportForSecureRequest creates a new TransportMessage with a SecureRequest as payload. The Transport will be the same version as the SecureRequest 265 func (fw *Framework) NewTransportForSecureRequest(request protocol.SecureRequest) (message protocol.TransportMessage, err error) { 266 switch request.Version() { 267 case protocol.SecureRequestV1: 268 message, err = v1.NewTransportMessage(fw.Config.Identity) 269 case protocol.SecureRequestV2: 270 message, err = v2.NewTransportMessage(fw.Config.Identity) 271 default: 272 return nil, fmt.Errorf("co not know how to create a Transport message for SecureRequest version %s", request.Version()) 273 } 274 275 if err != nil { 276 fw.log.Errorf("Failed to create transport from secure request: %s", err) 277 return nil, err 278 } 279 280 err = message.SetRequestData(request) 281 if err != nil { 282 fw.log.Errorf("Failed to create transport from secure request: %s", err) 283 return nil, err 284 } 285 286 return message, nil 287 } 288 289 // NewTransportForSecureReply creates a new TransportMessage with a SecureReply as payload. The Transport will be the same version as the SecureRequest 290 func (fw *Framework) NewTransportForSecureReply(reply protocol.SecureReply) (message protocol.TransportMessage, err error) { 291 switch reply.Version() { 292 case protocol.SecureReplyV1: 293 message, err = v1.NewTransportMessage(fw.Config.Identity) 294 case protocol.SecureReplyV2: 295 message, err = v2.NewTransportMessage(fw.Config.Identity) 296 default: 297 return nil, fmt.Errorf("do not know how to create a Transport message for SecureRequest version %s", reply.Version()) 298 } 299 300 if err != nil { 301 return nil, err 302 } 303 304 message.SetReplyData(reply) 305 306 return message, nil 307 } 308 309 // NewReplyTransportForMessage creates a new Transport message based on a Message and the request its a reply to 310 // 311 // The new transport message will have the same version as the request its based on 312 func (fw *Framework) NewReplyTransportForMessage(msg inter.Message, request protocol.Request) (protocol.TransportMessage, error) { 313 reply, err := fw.NewReply(request) 314 if err != nil { 315 return nil, fmt.Errorf("could not create Reply: %s", err) 316 } 317 318 reply.SetMessage(msg.Payload()) 319 320 sreply, err := fw.NewSecureReply(reply) 321 if err != nil { 322 return nil, fmt.Errorf("could not create Secure Reply: %s", err) 323 } 324 325 transport, err := fw.NewTransportForSecureReply(sreply) 326 if err != nil { 327 return nil, fmt.Errorf("could not create Transport: %s", err) 328 } 329 330 protocol.CopyFederationData(request, transport) 331 332 return transport, nil 333 } 334 335 // NewRequestTransportForMessage creates a new versioned Transport message based on a Message 336 func (fw *Framework) NewRequestTransportForMessage(ctx context.Context, msg inter.Message, version protocol.ProtocolVersion) (protocol.TransportMessage, error) { 337 req, err := fw.NewRequestFromMessage(version, msg) 338 if err != nil { 339 return nil, fmt.Errorf("could not create Request: %s", err) 340 } 341 342 sr, err := fw.NewSecureRequest(ctx, req) 343 if err != nil { 344 return nil, err 345 } 346 347 transport, err := fw.NewTransportForSecureRequest(sr) 348 if err != nil { 349 return nil, fmt.Errorf("could not create Transport: %s", err) 350 } 351 352 return transport, nil 353 } 354 355 // NewTransportMessage creates a new TransportMessage complying with a specific protocol version like protocol.TransportV1 356 func (fw *Framework) NewTransportMessage(version protocol.ProtocolVersion) (message protocol.TransportMessage, err error) { 357 switch version { 358 case protocol.TransportV1: 359 return v1.NewTransportMessage(fw.Config.Identity) 360 case protocol.TransportV2: 361 return v2.NewTransportMessage(fw.Config.Identity) 362 default: 363 return nil, fmt.Errorf("so not know how to create a Transport version '%s'", version) 364 } 365 } 366 367 // NewTransportFromJSON creates a new TransportMessage from a JSON payload. The version will match what is in the payload 368 func (fw *Framework) NewTransportFromJSON(data []byte) (message protocol.TransportMessage, err error) { 369 switch protocol.VersionFromJSON(data) { 370 case protocol.TransportV1: 371 return v1.NewTransportFromJSON(data) 372 case protocol.TransportV2: 373 return v2.NewTransportFromJSON(data) 374 default: 375 return nil, fmt.Errorf("do not know how to create a TransportMessage from an expected JSON format message with content: %s", data) 376 } 377 }