github.com/cs3org/reva/v2@v2.27.7/pkg/ctx/agentctx.go (about)

     1  // Copyright 2018-2021 CERN
     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  // In applying this license, CERN does not waive the privileges and immunities
    16  // granted to it by virtue of its status as an Intergovernmental Organization
    17  // or submit itself to any jurisdiction.
    18  
    19  package ctx
    20  
    21  import (
    22  	"context"
    23  	"strings"
    24  
    25  	ua "github.com/mileusna/useragent"
    26  	"google.golang.org/grpc/metadata"
    27  )
    28  
    29  // UserAgentHeader is the header used for the user agent
    30  const (
    31  	UserAgentHeader = "x-user-agent"
    32  
    33  	WebUserAgent     = "web"
    34  	GrpcUserAgent    = "grpc"
    35  	MobileUserAgent  = "mobile"
    36  	DesktopUserAgent = "desktop"
    37  )
    38  
    39  // ContextGetUserAgent returns the user agent if set in the given context.
    40  // see https://github.com/grpc/grpc-go/issues/1100
    41  func ContextGetUserAgent(ctx context.Context) (*ua.UserAgent, bool) {
    42  	if userAgentStr, ok := ContextGetUserAgentString(ctx); ok {
    43  		userAgent := ua.Parse(userAgentStr)
    44  		return &userAgent, true
    45  	}
    46  	return nil, false
    47  }
    48  
    49  // ContextGetUserAgentString returns the user agent string if set in the given context.
    50  func ContextGetUserAgentString(ctx context.Context) (string, bool) {
    51  	md, ok := metadata.FromIncomingContext(ctx)
    52  	if !ok {
    53  		return "", false
    54  	}
    55  	userAgentLst, ok := md[UserAgentHeader]
    56  	if !ok {
    57  		userAgentLst, ok = md["user-agent"]
    58  		if !ok {
    59  			return "", false
    60  		}
    61  	}
    62  	if len(userAgentLst) == 0 {
    63  		return "", false
    64  	}
    65  	return userAgentLst[0], true
    66  }
    67  
    68  // ContextGetUserAgentCategory returns the category of the user agent
    69  // (i.e. if it is a web, mobile, desktop or grpc user agent)
    70  func ContextGetUserAgentCategory(ctx context.Context) (string, bool) {
    71  	agent, ok := ContextGetUserAgent(ctx)
    72  	if !ok {
    73  		return "", false
    74  	}
    75  	switch {
    76  	case isWeb(agent):
    77  		return WebUserAgent, true
    78  	case isMobile(agent):
    79  		return MobileUserAgent, true
    80  	case isDesktop(agent):
    81  		return DesktopUserAgent, true
    82  	case isGRPC(agent):
    83  		return GrpcUserAgent, true
    84  	default:
    85  		return "", false
    86  	}
    87  }
    88  
    89  func isWeb(ua *ua.UserAgent) bool {
    90  	return ua.IsChrome() || ua.IsEdge() || ua.IsFirefox() || ua.IsSafari() ||
    91  		ua.IsInternetExplorer() || ua.IsOpera() || ua.IsOperaMini()
    92  }
    93  
    94  // isMobile returns true if the useragent is generated by the mobile
    95  func isMobile(ua *ua.UserAgent) bool {
    96  	// workaround as the library does not recognise iOS string inside the user agent
    97  	isIOS := ua.IsIOS() || strings.Contains(ua.String, "iOS")
    98  	return !isWeb(ua) && (ua.IsAndroid() || isIOS)
    99  }
   100  
   101  // isDesktop returns true if the useragent is generated by a desktop application
   102  func isDesktop(ua *ua.UserAgent) bool {
   103  	return ua.Desktop && !isWeb(ua)
   104  }
   105  
   106  // isGRPC returns true if the useragent is generated by a grpc client
   107  func isGRPC(ua *ua.UserAgent) bool {
   108  	return strings.HasPrefix(ua.Name, "grpc")
   109  }