github.com/keybase/client/go@v0.0.0-20241007131713-f10651d043c8/avatars/upload.go (about)

     1  // Copyright 2018 Keybase, Inc. All rights reserved. Use of
     2  // this source code is governed by the included BSD license.
     3  
     4  package avatars
     5  
     6  import (
     7  	"bytes"
     8  	"fmt"
     9  	"io"
    10  	"mime/multipart"
    11  	"os"
    12  	"time"
    13  
    14  	"github.com/keybase/client/go/libkb"
    15  	"github.com/keybase/client/go/protocol/keybase1"
    16  )
    17  
    18  func addFile(mpart *multipart.Writer, param, filename string) error {
    19  	file, err := os.Open(filename)
    20  	if err != nil {
    21  		return err
    22  	}
    23  	defer file.Close()
    24  
    25  	// do not disclose our filename to the server
    26  	part, err := mpart.CreateFormFile(param, "image" /* filename */)
    27  	if err != nil {
    28  		return err
    29  	}
    30  
    31  	_, err = io.Copy(part, file)
    32  	return err
    33  }
    34  
    35  func UploadImage(mctx libkb.MetaContext, filename string, teamID *keybase1.TeamID, crop *keybase1.ImageCropRect) (err error) {
    36  	var body bytes.Buffer
    37  	mpart := multipart.NewWriter(&body)
    38  
    39  	if err := addFile(mpart, "avatar", filename); err != nil {
    40  		mctx.Debug("addFile error: %s", err)
    41  		return err
    42  	}
    43  
    44  	// Server checks upload size as well.
    45  	const maxUploadSize = 20 * 1024 * 1024
    46  	if bodyLen := body.Len(); bodyLen > maxUploadSize {
    47  		return fmt.Errorf("Image is too big: tried to upload %d bytes, max size is %d bytes.",
    48  			bodyLen, maxUploadSize)
    49  	}
    50  
    51  	if teamID != nil {
    52  		err := mpart.WriteField("team_id", string(*teamID))
    53  		if err != nil {
    54  			return err
    55  		}
    56  	}
    57  
    58  	if crop != nil {
    59  		mctx.Debug("Adding crop fields: %+v", crop)
    60  		err := mpart.WriteField("x0", fmt.Sprintf("%d", crop.X0))
    61  		if err != nil {
    62  			return err
    63  		}
    64  		err = mpart.WriteField("y0", fmt.Sprintf("%d", crop.Y0))
    65  		if err != nil {
    66  			return err
    67  		}
    68  		err = mpart.WriteField("x1", fmt.Sprintf("%d", crop.X1))
    69  		if err != nil {
    70  			return err
    71  		}
    72  		err = mpart.WriteField("y1", fmt.Sprintf("%d", crop.Y1))
    73  		if err != nil {
    74  			return err
    75  		}
    76  	}
    77  
    78  	if err := mpart.Close(); err != nil {
    79  		return err
    80  	}
    81  
    82  	var endpoint string
    83  	if teamID != nil {
    84  		endpoint = "image/upload_team_avatar"
    85  	} else {
    86  		endpoint = "image/upload_user_avatar"
    87  	}
    88  
    89  	mctx.Debug("Running POST to %s", endpoint)
    90  
    91  	arg := libkb.APIArg{
    92  		Endpoint:       endpoint,
    93  		SessionType:    libkb.APISessionTypeREQUIRED,
    94  		InitialTimeout: 5 * time.Minute,
    95  		RetryCount:     1,
    96  	}
    97  
    98  	_, err = mctx.G().API.PostRaw(mctx, arg, mpart.FormDataContentType(), &body)
    99  	if err != nil {
   100  		mctx.Debug("post error: %s", err)
   101  		return err
   102  	}
   103  
   104  	return nil
   105  }