browser.ts 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164
  1. /**
  2. * This file is part of Threema Web.
  3. *
  4. * Threema Web is free software: you can redistribute it and/or modify it
  5. * under the terms of the GNU Affero General Public License as published by
  6. * the Free Software Foundation, either version 3 of the License, or (at
  7. * your option) any later version.
  8. *
  9. * This program is distributed in the hope that it will be useful, but
  10. * WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero
  12. * General Public License for more details.
  13. *
  14. * You should have received a copy of the GNU Affero General Public License
  15. * along with Threema Web. If not, see <http://www.gnu.org/licenses/>.
  16. */
  17. import {Logger} from 'ts-log';
  18. import {BrowserInfo} from '../helpers/browser_info';
  19. import {LogService} from './log';
  20. import BrowserName = threema.BrowserName;
  21. export class BrowserService {
  22. private browser: BrowserInfo;
  23. private $window: ng.IWindowService;
  24. private readonly log: Logger;
  25. private supportsExtendedLocaleCompareCache: boolean;
  26. public static $inject = ['$window', 'LogService'];
  27. constructor($window: ng.IWindowService, logService: LogService) {
  28. this.$window = $window;
  29. this.log = logService.getLogger('Browser-S');
  30. }
  31. public getBrowser(): BrowserInfo {
  32. if (this.browser === undefined) {
  33. const browser = {
  34. chrome: false,
  35. chromeIos: false,
  36. firefox: false,
  37. firefoxIos: false,
  38. ie: false,
  39. edge: false,
  40. opera: false,
  41. safari: false,
  42. };
  43. const uagent = this.$window.navigator.userAgent.toLowerCase();
  44. browser.chrome = /webkit/.test(uagent) && /chrome/.test(uagent) && !/edg/.test(uagent);
  45. browser.chromeIos = /mozilla/.test(uagent) && /crios/.test(uagent);
  46. browser.firefox = /mozilla/.test(uagent) && /firefox/.test(uagent);
  47. browser.firefoxIos = /mozilla/.test(uagent) && /fxios/.test(uagent);
  48. browser.ie = (/msie/.test(uagent) || /trident/.test(uagent)) && !/edge/.test(uagent);
  49. browser.edge = /edg/.test(uagent);
  50. browser.safari = /safari/.test(uagent) && /applewebkit/.test(uagent)
  51. && !/chrome/.test(uagent) && !/fxios/.test(uagent) && !/crios/.test(uagent);
  52. browser.opera = /mozilla/.test(uagent) && /applewebkit/.test(uagent)
  53. && /chrome/.test(uagent) && /safari/.test(uagent) && /opr/.test(uagent);
  54. if (browser.opera && browser.chrome) {
  55. browser.chrome = false;
  56. }
  57. let version = null;
  58. for (const x in browser) {
  59. if (browser[x]) {
  60. let b;
  61. if (x === 'ie') {
  62. b = 'msie';
  63. } else if (x === 'edge') {
  64. b = 'edge?';
  65. } else if (x === 'opera') {
  66. b = 'opr';
  67. } else if (x === 'firefoxIos') {
  68. b = 'fxios';
  69. } else if (x === 'chromeIos') {
  70. b = 'crios';
  71. } else if (x === 'safari') {
  72. b = 'version';
  73. } else {
  74. b = x;
  75. }
  76. let match = uagent.match(new RegExp('(' + b + ')( |\/)([0-9]+)'));
  77. let versionString;
  78. if (match) {
  79. versionString = match[3];
  80. } else {
  81. match = uagent.match(new RegExp('rv:([0-9]+)'));
  82. versionString = match ? match[1] : '';
  83. }
  84. const versionInt: number = parseInt(versionString, 10);
  85. version = isNaN(versionInt) ? undefined : versionInt;
  86. break;
  87. }
  88. }
  89. if (browser.chrome) {
  90. this.browser = new BrowserInfo(uagent, BrowserName.Chrome, version);
  91. }
  92. if (browser.chromeIos) {
  93. this.browser = new BrowserInfo(uagent, BrowserName.ChromeIos, version, true);
  94. }
  95. if (browser.firefox) {
  96. this.browser = new BrowserInfo(uagent, BrowserName.Firefox, version);
  97. }
  98. if (browser.firefoxIos) {
  99. this.browser = new BrowserInfo(uagent, BrowserName.FirefoxIos, version, true);
  100. }
  101. if (browser.ie) {
  102. this.browser = new BrowserInfo(uagent, BrowserName.InternetExplorer, version);
  103. }
  104. if (browser.edge) {
  105. this.browser = new BrowserInfo(uagent, BrowserName.Edge, version);
  106. }
  107. if (browser.safari) {
  108. const mobile = /mobile/.test(uagent);
  109. this.browser = new BrowserInfo(uagent, BrowserName.Safari, version, mobile);
  110. }
  111. if (browser.opera) {
  112. this.browser = new BrowserInfo(uagent, BrowserName.Opera, version);
  113. }
  114. }
  115. return this.browser;
  116. }
  117. /**
  118. * Return whether the current browser supports the WebRTC task or not.
  119. */
  120. public supportsWebrtcTask() {
  121. if (this.browser === undefined) {
  122. this.getBrowser();
  123. }
  124. return this.browser.supportsWebrtcTask();
  125. }
  126. /**
  127. * Return whether the browser supports extended `string.localeCompare` options.
  128. */
  129. public supportsExtendedLocaleCompare() {
  130. if (this.supportsExtendedLocaleCompareCache !== undefined) {
  131. return this.supportsExtendedLocaleCompareCache;
  132. }
  133. function getSupport(): boolean {
  134. try {
  135. 'foo'.localeCompare('bar', 'i');
  136. } catch (e) {
  137. return e.name === 'RangeError';
  138. }
  139. return false;
  140. }
  141. const support = getSupport();
  142. this.supportsExtendedLocaleCompareCache = support;
  143. this.log.debug(`Browser ${support ? 'supports' : 'does not support'} extended locale compare options`);
  144. return support;
  145. }
  146. }