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 }