github.com/greenpau/go-authcrunch@v1.1.4/pkg/authn/handle_http_apps.go (about)

     1  // Copyright 2022 Paul Greenberg greenpau@outlook.com
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package authn
    16  
    17  import (
    18  	"context"
    19  	"fmt"
    20  	"io"
    21  	"net/http"
    22  	"strings"
    23  
    24  	"github.com/greenpau/go-authcrunch/pkg/authn/enums/role"
    25  	"github.com/greenpau/go-authcrunch/pkg/authn/ui"
    26  	"github.com/greenpau/go-authcrunch/pkg/requests"
    27  	"github.com/greenpau/go-authcrunch/pkg/user"
    28  	"go.uber.org/zap"
    29  )
    30  
    31  func (p *Portal) handleHTTPApps(ctx context.Context, w http.ResponseWriter, r *http.Request, rr *requests.Request, usr *user.User, appName string) error {
    32  	p.disableClientCache(w)
    33  	p.injectRedirectURL(ctx, w, r, rr)
    34  	if usr == nil && !strings.HasSuffix(r.URL.Path, appName+"/manifest.json") {
    35  		p.logger.Debug("app asset download is unauthorized", zap.String("app_name", appName), zap.String("app_file_url_path", r.URL.Path))
    36  		return p.handleHTTPError(ctx, w, r, rr, http.StatusUnauthorized)
    37  	}
    38  
    39  	if err := p.authorizedRole(usr, []role.Kind{role.Admin, role.User}, rr.Response.Authenticated); err != nil {
    40  		if !strings.HasSuffix(r.URL.Path, appName+"/manifest.json") {
    41  			p.logger.Debug("app asset download is forbidden", zap.String("app_name", appName), zap.String("app_file_url_path", r.URL.Path))
    42  			return p.handleHTTPError(ctx, w, r, rr, http.StatusForbidden)
    43  		}
    44  	}
    45  
    46  	var assetPath string
    47  	switch {
    48  	case appName == "profile":
    49  		assetPath = strings.TrimPrefix(r.URL.Path, rr.Upstream.BasePath)
    50  		if !strings.HasPrefix(assetPath, "profile/") {
    51  			assetPath = appName + "/" + assetPath
    52  		}
    53  	default:
    54  		p.logger.Debug("asset download for unsupported app", zap.String("app_name", appName), zap.String("app_file_url_path", r.URL.Path))
    55  		return p.handleHTTPRenderError(ctx, w, r, rr, fmt.Errorf("file not found"))
    56  	}
    57  
    58  	p.logRequest(appName+" app assets", r, rr)
    59  	asset, err := ui.AppAssets.GetAsset(assetPath)
    60  	if err != nil {
    61  		if strings.HasSuffix(assetPath, "/") || strings.Count(assetPath, "/") >= 3 || strings.HasSuffix(assetPath, "/new") {
    62  			asset, err = ui.AppAssets.GetAsset(appName + "/")
    63  			if err != nil {
    64  				p.logger.Debug("app asset download not found", zap.String("app_name", appName), zap.String("app_file_url_path", r.URL.Path), zap.String("asset_path", assetPath))
    65  				return p.handleHTTPError(ctx, w, r, rr, http.StatusNotFound)
    66  			}
    67  		} else {
    68  			p.logger.Debug("app asset download not found", zap.String("app_name", appName), zap.String("app_file_url_path", r.URL.Path), zap.String("asset_path", assetPath))
    69  			return p.handleHTTPError(ctx, w, r, rr, http.StatusNotFound)
    70  		}
    71  	}
    72  
    73  	w.Header().Set("Content-Type", asset.ContentType)
    74  	w.Header().Set("Etag", asset.Checksum)
    75  	w.Header().Set("Cache-Control", "max-age=7200")
    76  	if match := r.Header.Get("If-None-Match"); match != "" {
    77  		if strings.Contains(match, asset.Checksum) {
    78  			w.WriteHeader(http.StatusNotModified)
    79  			return nil
    80  		}
    81  	}
    82  	w.WriteHeader(http.StatusOK)
    83  	io.WriteString(w, asset.Content)
    84  	return nil
    85  }