Compare commits

...

6 Commits

Author SHA1 Message Date
Rakov 8896df9f1f fix(refresh): refresh token fix 2 years ago
Rakov 10bca448dc fix(refresh): resfresh token fix 2 years ago
Rakov 7a2423568a fix(refresh): save refresh lff facr 2 years ago
Rakov ccb265cb2e Revert "fix(#699): auth token" 2 years ago
Rakov 3152372c39 fix(inposrt.live): insport.live makefile build 2 years ago
Rakov 4e43b9aea8 fix(insport.live): insport.live deploy 2 years ago
  1. 53
      .drone.yml
  2. 9
      Makefile
  3. 28
      public/silent-refresh.html
  4. 44
      src/features/AuthStore/hooks/useAuth.tsx
  5. 6
      src/features/SystemSettings/hooks.tsx
  6. 2
      src/helpers/cookie/index.tsx
  7. 13
      src/helpers/token/index.tsx
  8. 51
      src/requests/getCredentials.tsx

@ -1007,3 +1007,56 @@ steps:
- aws cloudfront create-invalidation --distribution-id E15IFY23VM147K --paths "/*"
depends_on:
- make-rustat
---
kind: pipeline
type: docker
name: deploy insport.live
concurrency:
limit: 1
platform:
os: linux
arch: amd64
trigger:
ref:
- refs/heads/insport.live
steps:
- name: npm-install
image: node:16-alpine
environment:
REACT_APP_STRIPE_PK:
from_secret: REACT_APP_STRIPE_PK
commands:
- apk add --no-cache make
- npm install --legacy-peer-deps
- name: make-insport-live
image: node:16-alpine
environment:
REACT_APP_STRIPE_PK:
from_secret: REACT_APP_STRIPE_PK
commands:
- apk add --no-cache make
- make insport-live-prod
depends_on:
- npm-install
- name: deploy-insport-live
image: amazon/aws-cli:latest
environment:
AWS_ACCESS_KEY_ID:
from_secret: AWS_ACCESS_KEY_ID
AWS_SECRET_ACCESS_KEY:
from_secret: AWS_SECRET_ACCESS_KEY
AWS_DEFAULT_REGION:
from_secret: AWS_DEFAULT_REGION
AWS_MAX_ATTEMPTS: 10
commands:
- aws s3 sync build_insport_live s3://insports-live --delete
- aws cloudfront create-invalidation --distribution-id E1LBC88VYP6XVB --paths "/*"
depends_on:
- make-insport-live

@ -225,6 +225,15 @@ rustat-prod:
BUILD_PATH=build_rustat \
npm run build && cp -r .well-known build_rustat
insport-live-prod:
rm -rf build_insport_live && \
REACT_APP_TYPE=ott \
REACT_APP_ENV=staging \
REACT_APP_CLIENT=lff \
REACT_APP_STRIPE_PK=pk_live_51J5TEYEDSxVnTgDW5XxhC6ntKZKddXgKHq5HOCDmJTdfSKluMYCdLHOcUA3Miuy8HesxG1eS4c0dQRQpMsEHRrQL00USpu5xIq \
BUILD_PATH=build_insport_live \
npm run build && cp -r .well-known build_insport_live
deploy-all: prod preprod facr-prod lff-prod diwansport-prod india-prod fqtv-prod rustat-prod
test:

@ -11,30 +11,12 @@
crossorigin="anonymous" referrerpolicy="no-referrer"></script>
<script>
new Oidc.UserManager().signinSilentCallback()
// обновляем рефреш токен в локалсторадже
// так как safari не дает доступ к кукам
.then(() => {
const refreshToken = new URLSearchParams(document.location.search).get('refresh_token');
if (refreshToken && /iPad|iPhone|iPod/.test(navigator.userAgent)) {
const getDomain = () => {
if (! '%NODE_ENV%' || '%NODE_ENV%' === 'development') {
return 'localhost';
} else {
return '.insports.tv';
}
};
const parseJwt = (value) => {
const base64Url = value.split('.')[1];
const base64 = base64Url.replace(/-/g, '+').replace(/_/g, '/');
const jsonPayload = decodeURIComponent(window.atob(base64).split('').map((c) => `%${(`00${c.charCodeAt(0).toString(16)}`).slice(-2)}`).join(''));
return JSON.parse(jsonPayload);
};
const saveRefreshToken = (value) => {
const ref = parseJwt(value);
const expires = `expires=${new Date((ref.exp * 1000)).toUTCString()}`;
document.cookie = `refresh_token=${value};${expires};path=/;domain=${getDomain()};secure;SameSite=None`;
};
saveRefreshToken(refreshToken);
const refreshToken = localStorage.getItem('refresh_token');
if (refreshToken) {
localStorage.setItem('refresh_token', new URLSearchParams(document.location.search).get('refresh_token'));
}
})
.catch((err) => {

@ -14,7 +14,7 @@ import isString from 'lodash/isString'
import isBoolean from 'lodash/isBoolean'
import includes from 'lodash/includes'
import { PAGES, isIOS } from 'config'
import { PAGES } from 'config'
import {
addLanguageUrlParam,
@ -24,7 +24,10 @@ import {
setCookie,
removeCookie,
isMatchPage,
getDomain,
REFRESH_TOKEN_KEY,
removeRefreshToken,
writeRefreshToken,
readRefreshToken,
} from 'helpers'
import {
@ -66,14 +69,6 @@ export const useAuth = () => {
})
}
const parseJwt = (value: string) => {
const base64Url = value.split('.')[1]
const base64 = base64Url.replace(/-/g, '+').replace(/_/g, '/')
const jsonPayload = decodeURIComponent(window.atob(base64).split('').map((c) => `%${(`00${c.charCodeAt(0).toString(16)}`).slice(-2)}`).join(''))
return JSON.parse(jsonPayload)
}
const login = useCallback(async () => {
userManager.signinRedirect({ extraQueryParams: { lang } })
}, [lang])
@ -86,9 +81,9 @@ export const useAuth = () => {
userManager.signoutRedirect({ post_logout_redirect_uri: urlWithLang })
})
removeToken()
removeRefreshToken()
if (key !== 'saveToken') {
removeCookie('access_token')
removeCookie('refresh_token')
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [lang])
@ -168,20 +163,14 @@ export const useAuth = () => {
}
}
const saveRefreshToken = (value: string) => {
const ref = parseJwt(value)
const expires = `expires=${new Date((ref.exp * 1000)).toUTCString()}`
document.cookie = `refresh_token=${value};${expires};path=/;domain=${getDomain()};secure;SameSite=None`
}
const signinRedirectCallback = useCallback(async (refreshToken: string | null) => {
const signinRedirectCallback = useCallback((refreshToken: string | null) => {
setPage(history.location.pathname)
userManager.signinRedirectCallback()
.then((loadedUser) => {
storeUser(loadedUser)
if (isIOS && refreshToken) saveRefreshToken(refreshToken)
if (refreshToken) writeRefreshToken(refreshToken)
queryParamStorage.clear()
if (page.includes(PAGES.useraccount)) {
@ -194,7 +183,7 @@ export const useAuth = () => {
setPage('')
setSearch('')
}).catch(login)
// eslint-disable-next-line react-hooks/exhaustive-deps
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [
login,
storeUser,
@ -206,14 +195,14 @@ export const useAuth = () => {
const searchToken = urlSearch.get('access_token')
const searchRefToken = urlSearch.get('id_token')
const searchExp = urlSearch.get('expires_in')
const refreshToken = urlSearch.get('refresh_token')
const refreshToken = urlSearch.get(REFRESH_TOKEN_KEY)
const isRedirectedBackFromAuthProvider = Boolean(searchToken && searchRefToken && searchExp)
isRedirectedBackFromAuthProvider
? signinRedirectCallback(refreshToken)
: checkUser()
// eslint-disable-next-line react-hooks/exhaustive-deps
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [
checkUser,
signinRedirectCallback,
@ -243,7 +232,7 @@ export const useAuth = () => {
}, [reChekNewDevice])
useEffect(() => {
if (!needCheckNewDeviсe && !user) return undefined
if (!needCheckNewDeviсe || !user) return undefined
const startCheckDevice = setInterval(checkNewDevice, 20000)
isNewDeviceLogin && clearInterval(startCheckDevice)
return () => clearInterval(startCheckDevice)
@ -253,6 +242,7 @@ export const useAuth = () => {
checkNewDevice,
isNewDeviceLogin,
setIsNewDeviceLogin,
user,
])
duel.channel('active_page') // поле в LS, определяющее активность вкладки
@ -262,7 +252,13 @@ export const useAuth = () => {
// библиотека oidc-client не поддерживает обновление токена только на 1 вкладке
// @ts-ignore
if (window.isMaster()) {
userManager.signinSilent().catch(logout)
// safari ограничивает доступ к куке через крос доменные запросы
// передаем рефреш токен через квери параметры
userManager.signinSilent({
extraQueryParams: {
refresh_token: readRefreshToken(),
},
}).catch(logout)
}
}
// если запросы вернули 401 | 403

@ -9,8 +9,8 @@ import { SELECTED_API_KEY } from 'helpers/selectedApi'
import { useToggle } from 'hooks/useToggle'
import { useLocalStore } from 'hooks/useStorage'
import { removeToken } from '../../helpers'
import { removeCookie } from '../../helpers/cookie'
import { removeRefreshToken, removeToken } from 'helpers'
import { removeCookie } from 'helpers/cookie'
type FormElement = HTMLFormElement & {
api: HTMLInputElement & {
@ -37,8 +37,8 @@ export const useSystemSettings = () => {
const { api } = e.currentTarget
setSelectedApi(api.value)
removeToken()
removeRefreshToken()
removeCookie('access_token')
removeCookie('refresh_token')
window.location.reload()
}

@ -29,7 +29,7 @@ export const checkCookie = (name: string) => {
return token[0]
}
export const getDomain = () => (
const getDomain = () => (
process.env.NODE_ENV === 'development'
? 'localhost'
: '.insports.tv'

@ -1,4 +1,5 @@
export const TOKEN_KEY = 'token'
export const REFRESH_TOKEN_KEY = 'refresh_token'
export const readToken = () => (
localStorage.getItem(TOKEN_KEY)
@ -11,3 +12,15 @@ export const writeToken = (token: string) => (
export const removeToken = () => (
localStorage.removeItem(TOKEN_KEY)
)
export const removeRefreshToken = () => {
localStorage.removeItem(REFRESH_TOKEN_KEY)
}
export const writeRefreshToken = (token: string) => (
localStorage.setItem(REFRESH_TOKEN_KEY, token)
)
export const readRefreshToken = () => (
localStorage.getItem(REFRESH_TOKEN_KEY)
)

@ -1,51 +0,0 @@
import { AUTH_SERVICE } from 'config'
import { ClientIds } from 'config/clients/types'
export type TokenFailedResponse = {
error?: {
code: number,
message: string,
},
ok: false,
}
type TokenResponse = {
access_token: string,
id_token: string,
refresh_token: string,
}
type TokenProps = {
client_id: ClientIds,
email?: 'string',
grant_type?: 'password' | 'refresh_token',
id_token?: 'string',
password?: 'string',
refresh_token: string,
}
export const getCredentials = async ({
client_id,
grant_type = 'refresh_token',
refresh_token,
}: TokenProps): Promise<TokenResponse> => {
const url = new URL(`${AUTH_SERVICE}/token`)
const credetials = await fetch(url, {
body: JSON.stringify({
client_id,
grant_type,
refresh_token,
}),
headers: {
'Content-Type': 'application/json',
},
method: 'POST',
})
const body: TokenResponse | TokenFailedResponse = await credetials.json()
if ('ok' in body) return Promise.reject(body.error)
return Promise.resolve(body)
}
Loading…
Cancel
Save