1
1
mirror of https://github.com/go-gitea/gitea synced 2025-07-15 23:17:19 +00:00

Handle CORS requests (#6289)

This commit is contained in:
Tamal Saha
2019-05-13 08:38:53 -07:00
committed by techknowlogick
parent 6fb58a8cdc
commit 34d06f4c6b
170 changed files with 5220 additions and 2124 deletions

View File

@@ -25,10 +25,22 @@ import (
"math/big"
"sync"
"crypto"
"golang.org/x/crypto/ed25519"
"golang.org/x/crypto/ssh"
)
// SignatureFlags represent additional flags that can be passed to the signature
// requests an defined in [PROTOCOL.agent] section 4.5.1.
type SignatureFlags uint32
// SignatureFlag values as defined in [PROTOCOL.agent] section 5.3.
const (
SignatureFlagReserved SignatureFlags = 1 << iota
SignatureFlagRsaSha256
SignatureFlagRsaSha512
)
// Agent represents the capabilities of an ssh-agent.
type Agent interface {
// List returns the identities known to the agent.
@@ -57,6 +69,26 @@ type Agent interface {
Signers() ([]ssh.Signer, error)
}
type ExtendedAgent interface {
Agent
// SignWithFlags signs like Sign, but allows for additional flags to be sent/received
SignWithFlags(key ssh.PublicKey, data []byte, flags SignatureFlags) (*ssh.Signature, error)
// Extension processes a custom extension request. Standard-compliant agents are not
// required to support any extensions, but this method allows agents to implement
// vendor-specific methods or add experimental features. See [PROTOCOL.agent] section 4.7.
// If agent extensions are unsupported entirely this method MUST return an
// ErrExtensionUnsupported error. Similarly, if just the specific extensionType in
// the request is unsupported by the agent then ErrExtensionUnsupported MUST be
// returned.
//
// In the case of success, since [PROTOCOL.agent] section 4.7 specifies that the contents
// of the response are unspecified (including the type of the message), the complete
// response will be returned as a []byte slice, including the "type" byte of the message.
Extension(extensionType string, contents []byte) ([]byte, error)
}
// ConstraintExtension describes an optional constraint defined by users.
type ConstraintExtension struct {
// ExtensionName consist of a UTF-8 string suffixed by the
@@ -179,6 +211,23 @@ type constrainExtensionAgentMsg struct {
Rest []byte `ssh:"rest"`
}
// See [PROTOCOL.agent], section 4.7
const agentExtension = 27
const agentExtensionFailure = 28
// ErrExtensionUnsupported indicates that an extension defined in
// [PROTOCOL.agent] section 4.7 is unsupported by the agent. Specifically this
// error indicates that the agent returned a standard SSH_AGENT_FAILURE message
// as the result of a SSH_AGENTC_EXTENSION request. Note that the protocol
// specification (and therefore this error) does not distinguish between a
// specific extension being unsupported and extensions being unsupported entirely.
var ErrExtensionUnsupported = errors.New("agent: extension unsupported")
type extensionAgentMsg struct {
ExtensionType string `sshtype:"27"`
Contents []byte
}
// Key represents a protocol 2 public key as defined in
// [PROTOCOL.agent], section 2.5.2.
type Key struct {
@@ -260,7 +309,7 @@ type client struct {
// NewClient returns an Agent that talks to an ssh-agent process over
// the given connection.
func NewClient(rw io.ReadWriter) Agent {
func NewClient(rw io.ReadWriter) ExtendedAgent {
return &client{conn: rw}
}
@@ -268,6 +317,21 @@ func NewClient(rw io.ReadWriter) Agent {
// unmarshaled into reply and replyType is set to the first byte of
// the reply, which contains the type of the message.
func (c *client) call(req []byte) (reply interface{}, err error) {
buf, err := c.callRaw(req)
if err != nil {
return nil, err
}
reply, err = unmarshal(buf)
if err != nil {
return nil, clientErr(err)
}
return reply, nil
}
// callRaw sends an RPC to the agent. On success, the raw
// bytes of the response are returned; no unmarshalling is
// performed on the response.
func (c *client) callRaw(req []byte) (reply []byte, err error) {
c.mu.Lock()
defer c.mu.Unlock()
@@ -284,18 +348,14 @@ func (c *client) call(req []byte) (reply interface{}, err error) {
}
respSize := binary.BigEndian.Uint32(respSizeBuf[:])
if respSize > maxAgentResponseBytes {
return nil, clientErr(err)
return nil, clientErr(errors.New("response too large"))
}
buf := make([]byte, respSize)
if _, err = io.ReadFull(c.conn, buf); err != nil {
return nil, clientErr(err)
}
reply, err = unmarshal(buf)
if err != nil {
return nil, clientErr(err)
}
return reply, err
return buf, nil
}
func (c *client) simpleCall(req []byte) error {
@@ -369,9 +429,14 @@ func (c *client) List() ([]*Key, error) {
// Sign has the agent sign the data using a protocol 2 key as defined
// in [PROTOCOL.agent] section 2.6.2.
func (c *client) Sign(key ssh.PublicKey, data []byte) (*ssh.Signature, error) {
return c.SignWithFlags(key, data, 0)
}
func (c *client) SignWithFlags(key ssh.PublicKey, data []byte, flags SignatureFlags) (*ssh.Signature, error) {
req := ssh.Marshal(signRequestAgentMsg{
KeyBlob: key.Marshal(),
Data: data,
Flags: uint32(flags),
})
msg, err := c.call(req)
@@ -681,3 +746,44 @@ func (s *agentKeyringSigner) Sign(rand io.Reader, data []byte) (*ssh.Signature,
// The agent has its own entropy source, so the rand argument is ignored.
return s.agent.Sign(s.pub, data)
}
func (s *agentKeyringSigner) SignWithOpts(rand io.Reader, data []byte, opts crypto.SignerOpts) (*ssh.Signature, error) {
var flags SignatureFlags
if opts != nil {
switch opts.HashFunc() {
case crypto.SHA256:
flags = SignatureFlagRsaSha256
case crypto.SHA512:
flags = SignatureFlagRsaSha512
}
}
return s.agent.SignWithFlags(s.pub, data, flags)
}
// Calls an extension method. It is up to the agent implementation as to whether or not
// any particular extension is supported and may always return an error. Because the
// type of the response is up to the implementation, this returns the bytes of the
// response and does not attempt any type of unmarshalling.
func (c *client) Extension(extensionType string, contents []byte) ([]byte, error) {
req := ssh.Marshal(extensionAgentMsg{
ExtensionType: extensionType,
Contents: contents,
})
buf, err := c.callRaw(req)
if err != nil {
return nil, err
}
if len(buf) == 0 {
return nil, errors.New("agent: failure; empty response")
}
// [PROTOCOL.agent] section 4.7 indicates that an SSH_AGENT_FAILURE message
// represents an agent that does not support the extension
if buf[0] == agentFailure {
return nil, ErrExtensionUnsupported
}
if buf[0] == agentExtensionFailure {
return nil, errors.New("agent: generic extension failure")
}
return buf, nil
}