This is a function responsible for generating a client configuration file. It leverages the Gin framework to handle HTTP requests and extracts information like operating system, architecture, host, port, and path from the request parameters. Subsequently, it opens a pre-built template file, reads its content, and replaces the encrypted configuration data within. Finally, it sets the HTTP response headers and writes the output to the HTTP response body. If errors occur at any stage, it returns corresponding HTTP error responses.

func GenerateClient(ctx *gin.Context) {
	var form struct {
		OS     string `json:'os' yaml:'os' form:'os' binding:'required'`
		Arch   string `json:'arch' yaml:'arch' form:'arch' binding:'required'`
		Host   string `json:'host' yaml:'host' form:'host' binding:'required'`
		Port   uint16 `json:'port' yaml:'port' form:'port' binding:'required'`
		Path   string `json:'path' yaml:'path' form:'path' binding:'required'`
		Secure string `json:'secure' yaml:'secure' form:'secure'`
	}
	if err := ctx.ShouldBind(&form); err != nil {
		ctx.AbortWithStatusJSON(http.StatusBadRequest, modules.Packet{Code: -1, Msg: `${i18n|COMMON.INVALID_PARAMETER}`})
		return
	}
	tpl, err := os.Open(fmt.Sprintf(config.BuiltPath, form.OS, form.Arch))
	if err != nil {
		ctx.AbortWithStatusJSON(http.StatusNotFound, modules.Packet{Code: 1, Msg: `${i18n|GENERATOR.NO_PREBUILT_FOUND}`})
		return
	}
	defer tpl.Close()
	clientUUID := utils.GetUUID()
	clientKey, err := common.EncAES(clientUUID, config.Config.SaltBytes)
	if err != nil {
		ctx.AbortWithStatusJSON(http.StatusInternalServerError, modules.Packet{Code: 1, Msg: `${i18n|GENERATOR.CONFIG_GENERATE_FAILED}`})
		return
	}
	cfgBytes, err := genConfig(clientCfg{
		Secure: form.Secure == 'true',
		Host:   form.Host,
		Port:   int(form.Port),
		Path:   form.Path,
		UUID:   hex.EncodeToString(clientUUID),
		Key:    hex.EncodeToString(clientKey),
	})
	if err != nil {
		if err == ErrTooLargeEntity {
			ctx.AbortWithStatusJSON(http.StatusRequestEntityTooLarge, modules.Packet{Code: 1, Msg: `${i18n|GENERATOR.CONFIG_TOO_LARGE}`})
			return
		}
		ctx.AbortWithStatusJSON(http.StatusInternalServerError, modules.Packet{Code: 1, Msg: `${i18n|GENERATOR.CONFIG_GENERATE_FAILED}`})
		return
	}
	ctx.Header('Accept-Ranges', 'none')
	ctx.Header('Content-Transfer-Encoding', 'binary')
	ctx.Header('Content-Type', 'application/octet-stream')
	if stat, err := tpl.Stat(); err == nil {
		ctx.Header('Content-Length', strconv.FormatInt(stat.Size(), 10))
	}
	if form.OS == 'windows' {
		ctx.Header('Content-Disposition', 'attachment; filename=client.exe; filename*=UTF-8''client.exe')
	} else {
		ctx.Header('Content-Disposition', 'attachment; filename=client; filename*=UTF-8''client')
	}
	// Find and replace plain buffer with encrypted configuration.
	cfgBuffer := bytes.Repeat([]byte{''}, 384)
	prevBuffer := make([]byte, 0)
	for {
		thisBuffer := make([]byte, 1024)
		n, err := tpl.Read(thisBuffer)
		thisBuffer = thisBuffer[:n]
		tempBuffer := append(prevBuffer, thisBuffer...)
		bufIndex := bytes.Index(tempBuffer, cfgBuffer)
		if bufIndex > -1 {
			tempBuffer = bytes.Replace(tempBuffer, cfgBuffer, cfgBytes, -1)
		}
		ctx.Writer.Write(tempBuffer[:len(prevBuffer)])
		prevBuffer = tempBuffer[len(prevBuffer):]
		if err != nil {
			break
		}
	}
	if len(prevBuffer) > 0 {
		ctx.Writer.Write(prevBuffer)
		prevBuffer = nil
	}
}
Generate Client Configuration File with Gin Framework

原文地址: https://www.cveoy.top/t/topic/lSbt 著作权归作者所有。请勿转载和采集!

免费AI点我,无需注册和登录