package handlers import ( "encoding/json" "net/http" "otaupdate/utils" "time" "github.com/fiskerinc/cloud-services/pkg/common" "github.com/fiskerinc/cloud-services/pkg/logger" "github.com/fiskerinc/cloud-services/pkg/remotefileupload" "github.com/Azure/azure-storage-blob-go/azblob" "github.com/julienschmidt/httprouter" "github.com/pkg/errors" "github.com/fiskerinc/cloud-services/pkg/loggerdataresp" ) // Need this so the swagger can use m var _ = common.APIToken{} // HandleTrexLogsLinkGet godoc // @Summary Retrieve T.Rex logs // @Description Get T.Rex logs for specific day // @Accept json // @Produce json // @Param Authorization header string false "Bearer " // @Param Api-Key header string false "" // @Param vin path string true "Car vin" // @Param year query string true "Year of file" // @Param month query string true "Month of file" // @Param day query string true "Day of file" // @Success 200 {object} LinkResponse // @Failure 400 {object} common.JSONError "Bad request" // @Failure 401 {object} common.JSONError "Unauthorized" // @Failure 404 {object} common.JSONError "Status not found" // @Failure 503 {object} common.JSONError "Service unavailable" // @Router /vehicle/{vin}/trex-logs-link [get] func HandleTrexLogsLinkGet(w http.ResponseWriter, r *http.Request) { params := httprouter.ParamsFromContext(r.Context()) vin := params.ByName("vin") query := r.URL.Query() year := query.Get("year") month := query.Get("month") day := query.Get("day") if vin == "" || year == "" || month == "" || day == "" { http.Error(w, "incomplete parameters", http.StatusBadRequest) return } // We are trusting the date is good, otherwise the user will get a download to nothing str, err := getAzureTRexBlobLink(vin, year, month, day) if loggerdataresp.BadDataErrorResp(w, err, http.StatusBadRequest) { return } encoder := json.NewEncoder(w) encoder.SetEscapeHTML(false) // Otherwise & becomes /00 encoded err = encoder.Encode(LinkResponse{Link: str}) if loggerdataresp.BadDataErrorResp(w, err, http.StatusBadRequest) { return } } type LinkResponse struct { Link string } func getAzureTRexBlobLink(vin, year, month, day string) (link string, err error) { link, err = remotefileupload.AzureFilePathLink(utils.AzureAccount, utils.AzureTRexLogsContainerName, vin, year, month, day, "raw.log") if err != nil { logger.Err(err).Msg("") } sasToken, err := getSASAccessTokenOnceADay() if err != nil { logger.Err(err).Msg("") } return link + "?" + sasToken, err } // We will fetch the access token once a day to prevent access to the files if someone saves a link somewhere accidentally var cachedTokenTime time.Time // The Time we last got the token var cachedToken string // Once a day get a new access token func getSASAccessTokenOnceADay() (token string, err error) { if time.Since(cachedTokenTime) > time.Hour*24 { cachedTokenTime = time.Now() cachedToken, err = generateSASToken() } return cachedToken, err } func generateSASToken() (token string, err error) { cred, err := azblob.NewSharedKeyCredential(utils.AzureAccount, utils.AzureAccountKey) if err != nil { return "", errors.WithStack(err) } sasQueryParams, err := azblob.BlobSASSignatureValues{ Protocol: azblob.SASProtocolHTTPS, StartTime: time.Now().UTC(), ExpiryTime: time.Now().UTC().Add(48 * time.Hour), Permissions: azblob.BlobSASPermissions{Read: true, List: true}.String(), IPRange: azblob.IPRange{}, ContainerName: utils.AzureTRexLogsContainerName, }.NewSASQueryParameters(cred) if err != nil { logger.Error().Err(err).Msg("Failed to sas.BlobSignatureValues") return } token = sasQueryParams.Encode() return }