diff --git a/api/graphql/auth/auth.go b/api/graphql/auth/auth.go index 4c82ba9a..90aa085d 100644 --- a/api/graphql/auth/auth.go +++ b/api/graphql/auth/auth.go @@ -27,31 +27,24 @@ func Middleware(db *sql.DB) func(http.Handler) http.Handler { return func(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - bearer := r.Header.Get("Authorization") - if bearer == "" { - next.ServeHTTP(w, r) - return + if tokenCookie, err := r.Cookie("auth-token"); err == nil { + log.Println("Found auth-token cookie") + user, err := models.VerifyTokenAndGetUser(db, tokenCookie.Value) + if err != nil { + log.Printf("Invalid token: %s\n", err) + http.Error(w, "invalid authorization token", http.StatusForbidden) + return + } + + // put it in context + ctx := context.WithValue(r.Context(), userCtxKey, user) + + // and call the next with our new context + r = r.WithContext(ctx) + } else { + log.Println("Did not find auth-token cookie") } - token, err := TokenFromBearer(&bearer) - if err != nil { - log.Printf("Invalid bearer format: %s\n", bearer) - http.Error(w, "Invalid authorization header format", http.StatusBadRequest) - return - } - - user, err := models.VerifyTokenAndGetUser(db, *token) - if err != nil { - log.Printf("Invalid token: %s\n", err) - http.Error(w, "Invalid authorization token", http.StatusForbidden) - return - } - - // put it in context - ctx := context.WithValue(r.Context(), userCtxKey, user) - - // and call the next with our new context - r = r.WithContext(ctx) next.ServeHTTP(w, r) }) } diff --git a/api/routes/authenticate_media.go b/api/routes/authenticate_media.go new file mode 100644 index 00000000..7b707c9e --- /dev/null +++ b/api/routes/authenticate_media.go @@ -0,0 +1,79 @@ +package routes + +import ( + "database/sql" + "net/http" + + "github.com/viktorstrate/photoview/api/graphql/auth" + "github.com/viktorstrate/photoview/api/graphql/models" + "golang.org/x/crypto/bcrypt" +) + +func authenticateMedia(media *models.Media, db *sql.DB, r *http.Request) (success bool, responseMessage string, responseStatus int, errorMessage error) { + user := auth.UserFromContext(r.Context()) + + if user != nil { + row := db.QueryRow("SELECT owner_id FROM album WHERE album.album_id = ?", media.AlbumId) + var owner_id int + + if err := row.Scan(&owner_id); err != nil { + return false, "internal server error", http.StatusInternalServerError, err + } + + if owner_id != user.UserID { + return false, "invalid credentials", http.StatusForbidden, nil + } + } else { + // Check if photo is authorized with a share token + token := r.URL.Query().Get("token") + if token == "" { + return false, "unauthorized", http.StatusForbidden, nil + } + + row := db.QueryRow("SELECT * FROM share_token WHERE value = ?", token) + + shareToken, err := models.NewShareTokenFromRow(row) + if err != nil { + return false, "internal server error", http.StatusInternalServerError, err + } + + // Validate share token password, if set + if shareToken.Password != nil { + tokenPassword := r.Header.Get("TokenPassword") + + if err := bcrypt.CompareHashAndPassword([]byte(*shareToken.Password), []byte(tokenPassword)); err != nil { + if err == bcrypt.ErrMismatchedHashAndPassword { + return false, "unauthorized", http.StatusForbidden, nil + } else { + return false, "internal server error", http.StatusInternalServerError, err + } + } + } + + if shareToken.AlbumID != nil && media.AlbumId != *shareToken.AlbumID { + // Check child albums + row := db.QueryRow(` + WITH recursive child_albums AS ( + SELECT * FROM album WHERE parent_album = ? + UNION ALL + SELECT child.* FROM album child JOIN child_albums parent ON parent.album_id = child.parent_album + ) + SELECT * FROM child_albums WHERE album_id = ? + `, *shareToken.AlbumID, media.AlbumId) + + _, err := models.NewAlbumFromRow(row) + if err != nil { + if err == sql.ErrNoRows { + return false, "unauthorized", http.StatusForbidden, nil + } + return false, "internal server error", http.StatusInternalServerError, err + } + } + + if shareToken.MediaID != nil && media.MediaID != *shareToken.MediaID { + return false, "unauthorized", http.StatusForbidden, nil + } + } + + return true, "success", http.StatusAccepted, nil +} diff --git a/api/routes/photos.go b/api/routes/photos.go index d418fb81..6c75857c 100644 --- a/api/routes/photos.go +++ b/api/routes/photos.go @@ -11,9 +11,7 @@ import ( "strconv" "github.com/gorilla/mux" - "golang.org/x/crypto/bcrypt" - "github.com/viktorstrate/photoview/api/graphql/auth" "github.com/viktorstrate/photoview/api/graphql/models" "github.com/viktorstrate/photoview/api/scanner" ) @@ -43,90 +41,13 @@ func RegisterPhotoRoutes(db *sql.DB, router *mux.Router) { w.Write([]byte("internal server error")) } - user := auth.UserFromContext(r.Context()) - if user != nil { - row := db.QueryRow("SELECT owner_id FROM album WHERE album.album_id = ?", media.AlbumId) - var owner_id int - - if err := row.Scan(&owner_id); err != nil { - log.Printf("WARN: %s", err) - w.WriteHeader(http.StatusInternalServerError) - w.Write([]byte("internal server error")) - return - } - - if owner_id != user.UserID { - w.WriteHeader(http.StatusForbidden) - w.Write([]byte("invalid credentials")) - return - } - } else { - // Check if photo is authorized with a share token - token := r.URL.Query().Get("token") - if token == "" { - w.WriteHeader(http.StatusForbidden) - w.Write([]byte("unauthorized")) - return - } - - row := db.QueryRow("SELECT * FROM share_token WHERE value = ?", token) - - shareToken, err := models.NewShareTokenFromRow(row) + if success, response, status, err := authenticateMedia(media, db, r); !success { if err != nil { - log.Printf("WARN: %s", err) - w.WriteHeader(http.StatusInternalServerError) - w.Write([]byte("internal server error")) - return + log.Printf("WARN: error authenticating photo: %s\n", err) } - - // Validate share token password, if set - if shareToken.Password != nil { - tokenPassword := r.Header.Get("TokenPassword") - - if err := bcrypt.CompareHashAndPassword([]byte(*shareToken.Password), []byte(tokenPassword)); err != nil { - if err == bcrypt.ErrMismatchedHashAndPassword { - w.WriteHeader(http.StatusForbidden) - w.Write([]byte("unauthorized")) - return - } else { - w.WriteHeader(http.StatusInternalServerError) - w.Write([]byte("internal server error")) - return - } - } - } - - if shareToken.AlbumID != nil && media.AlbumId != *shareToken.AlbumID { - // Check child albums - row := db.QueryRow(` - WITH recursive child_albums AS ( - SELECT * FROM album WHERE parent_album = ? - UNION ALL - SELECT child.* FROM album child JOIN child_albums parent ON parent.album_id = child.parent_album - ) - SELECT * FROM child_albums WHERE album_id = ? - `, *shareToken.AlbumID, media.AlbumId) - - _, err := models.NewAlbumFromRow(row) - if err != nil { - if err == sql.ErrNoRows { - w.WriteHeader(http.StatusForbidden) - w.Write([]byte("unauthorized")) - return - } - log.Printf("WARN: %s", err) - w.WriteHeader(http.StatusInternalServerError) - w.Write([]byte("internal server error")) - return - } - } - - if shareToken.MediaID != nil && media_id != *shareToken.MediaID { - w.WriteHeader(http.StatusForbidden) - w.Write([]byte("unauthorized")) - return - } - + w.WriteHeader(status) + w.Write([]byte(response)) + return } var cachedPath string diff --git a/api/routes/videos.go b/api/routes/videos.go index f4f05fc1..240cfc1e 100644 --- a/api/routes/videos.go +++ b/api/routes/videos.go @@ -38,6 +38,16 @@ func RegisterVideoRoutes(db *sql.DB, router *mux.Router) { } // TODO: Make sure user is authorized to access video + if success, response, status, err := authenticateMedia(media, db, r); !success { + if err != nil { + log.Printf("WARN: error authenticating video: %s\n", err) + } + w.WriteHeader(status) + w.Write([]byte(response)) + return + } + + log.Printf("Video cookies: %d", len(r.Cookies())) var cachedPath string diff --git a/api/server/cors_middleware.go b/api/server/cors_middleware.go index 007ee380..419e0f52 100644 --- a/api/server/cors_middleware.go +++ b/api/server/cors_middleware.go @@ -18,6 +18,7 @@ func CORSMiddleware(devMode bool) mux.MiddlewareFunc { w.Header().Set("Access-Control-Allow-Methods", strings.Join(methods, ",")) w.Header().Set("Access-Control-Allow-Headers", strings.Join(headers, ",")) + w.Header().Set("Access-Control-Allow-Credentials", "true") w.Header().Set("Access-Control-Expose-Headers", "content-length") endpoint := utils.ApiEndpointUrl() diff --git a/ui/src/AuthorizedRoute.js b/ui/src/AuthorizedRoute.js index 967c7c1e..ca9c75f4 100644 --- a/ui/src/AuthorizedRoute.js +++ b/ui/src/AuthorizedRoute.js @@ -3,6 +3,7 @@ import PropTypes from 'prop-types' import { Route, Redirect } from 'react-router-dom' import gql from 'graphql-tag' import { Query } from 'react-apollo' +import { authToken } from './authentication' const adminQuery = gql` query adminQuery { @@ -13,13 +14,13 @@ const adminQuery = gql` ` export const Authorized = ({ children }) => { - const token = localStorage.getItem('token') + const token = authToken() return token ? children : null } const AuthorizedRoute = ({ component: Component, admin = false, ...props }) => { - const token = localStorage.getItem('token') + const token = authToken() let unauthorizedRedirect = null if (!token) { diff --git a/ui/src/Pages/LoginPage/InitialSetupPage.js b/ui/src/Pages/LoginPage/InitialSetupPage.js index 07b07ac2..be15f7e1 100644 --- a/ui/src/Pages/LoginPage/InitialSetupPage.js +++ b/ui/src/Pages/LoginPage/InitialSetupPage.js @@ -6,6 +6,7 @@ import { Button, Form, Message, Header } from 'semantic-ui-react' import { Container } from './LoginPage' import { checkInitialSetupQuery, login } from './loginUtilFunctions' +import { authToken } from '../../authentication' const initialSetupMutation = gql` mutation InitialSetup( @@ -53,7 +54,7 @@ class InitialSetupPage extends Component { } render() { - if (localStorage.getItem('token')) { + if (authToken()) { return } diff --git a/ui/src/Pages/LoginPage/LoginPage.js b/ui/src/Pages/LoginPage/LoginPage.js index 270766c5..f7abbf20 100644 --- a/ui/src/Pages/LoginPage/LoginPage.js +++ b/ui/src/Pages/LoginPage/LoginPage.js @@ -11,6 +11,7 @@ import { Header, } from 'semantic-ui-react' import { checkInitialSetupQuery, login } from './loginUtilFunctions' +import { authToken } from '../../authentication' import logoPath from '../../assets/photoview-logo.svg' @@ -69,7 +70,7 @@ class LoginPage extends Component { } render() { - if (localStorage.getItem('token')) { + if (authToken()) { return } diff --git a/ui/src/Pages/LoginPage/loginUtilFunctions.js b/ui/src/Pages/LoginPage/loginUtilFunctions.js index 8a112630..8903f40c 100644 --- a/ui/src/Pages/LoginPage/loginUtilFunctions.js +++ b/ui/src/Pages/LoginPage/loginUtilFunctions.js @@ -1,4 +1,5 @@ import gql from 'graphql-tag' +import { saveTokenCookie } from '../../authentication' export const checkInitialSetupQuery = gql` query CheckInitialSetup { @@ -9,6 +10,6 @@ export const checkInitialSetupQuery = gql` ` export function login(token) { - localStorage.setItem('token', token) + saveTokenCookie(token) window.location = '/' } diff --git a/ui/src/Pages/SharePage/MediaSharePage.js b/ui/src/Pages/SharePage/MediaSharePage.js index 96209e69..197fb250 100644 --- a/ui/src/Pages/SharePage/MediaSharePage.js +++ b/ui/src/Pages/SharePage/MediaSharePage.js @@ -30,7 +30,12 @@ const MediaView = ({ media }) => { if (media.type == 'video') { return ( - + ) diff --git a/ui/src/Routes.js b/ui/src/Routes.js index 8ce867c8..63a568a3 100644 --- a/ui/src/Routes.js +++ b/ui/src/Routes.js @@ -3,6 +3,7 @@ import { Route, Switch, Redirect } from 'react-router-dom' import { Loader } from 'semantic-ui-react' import Layout from './Layout' +import { clearTokenCookie } from './authentication' const AlbumsPage = React.lazy(() => import('./Pages/AllAlbumsPage/AlbumsPage')) const AlbumPage = React.lazy(() => import('./Pages/AlbumPage/AlbumPage')) @@ -33,7 +34,7 @@ class Routes extends React.Component { {() => { - localStorage.removeItem('token') + clearTokenCookie() location.href = '/' }} diff --git a/ui/src/apolloClient.js b/ui/src/apolloClient.js index a9253ab6..5cdd372e 100644 --- a/ui/src/apolloClient.js +++ b/ui/src/apolloClient.js @@ -8,14 +8,15 @@ import { ApolloLink, split } from 'apollo-link' import { getMainDefinition } from 'apollo-utilities' import { MessageState } from './components/messages/Messages' import urlJoin from 'url-join' +import { clearTokenCookie } from './authentication' -const GRAPHQL_ENDPOINT = process.env.API_ENDPOINT +export const GRAPHQL_ENDPOINT = process.env.API_ENDPOINT ? urlJoin(process.env.API_ENDPOINT, '/graphql') : urlJoin(location.origin, '/api/graphql') const httpLink = new HttpLink({ uri: GRAPHQL_ENDPOINT, - credentials: 'same-origin', + credentials: 'include', }) console.log('GRAPHQL ENDPOINT', GRAPHQL_ENDPOINT) @@ -27,13 +28,7 @@ websocketUri.protocol = apiProtocol === 'https:' ? 'wss:' : 'ws:' const wsLink = new WebSocketLink({ uri: websocketUri, - credentials: 'same-origin', - options: { - reconnect: true, - connectionParams: { - Authorization: `Bearer ${localStorage.getItem('token')}`, - }, - }, + credentials: 'include', }) const link = split( @@ -76,7 +71,7 @@ const linkError = onError(({ graphQLErrors, networkError }) => { if (networkError) { console.log(`[Network error]: ${JSON.stringify(networkError)}`) - localStorage.removeItem('token') + clearTokenCookie() const errors = networkError.result.errors @@ -106,20 +101,9 @@ const linkError = onError(({ graphQLErrors, networkError }) => { } }) -const authLink = setContext((_, { headers }) => { - // get the authentication token from local storage if it exists - const token = localStorage.getItem('token') - // return the headers to the context so httpLink can read them - return { - headers: { - ...headers, - authorization: token ? `Bearer ${token}` : '', - }, - } -}) - const client = new ApolloClient({ - link: ApolloLink.from([linkError, authLink.concat(link)]), + // link: ApolloLink.from([linkError, authLink.concat(link)]), + link: ApolloLink.from([linkError, link]), cache: new InMemoryCache(), }) diff --git a/ui/src/authentication.js b/ui/src/authentication.js new file mode 100644 index 00000000..bfa2c422 --- /dev/null +++ b/ui/src/authentication.js @@ -0,0 +1,14 @@ +export function saveTokenCookie(token) { + const maxAge = 14 * 24 * 60 * 60 + + document.cookie = `auth-token=${token} ;max-age=${maxAge} ;path=/ ;sameSite=Lax` +} + +export function clearTokenCookie() { + document.cookie = 'auth-token= ;max-age=0' +} + +export function authToken() { + const match = document.cookie.match(/auth-token=([\d\w]+)/) + return match && match[1] +} diff --git a/ui/src/components/AlbumTitle.js b/ui/src/components/AlbumTitle.js index 8679545f..2e58dcf5 100644 --- a/ui/src/components/AlbumTitle.js +++ b/ui/src/components/AlbumTitle.js @@ -8,6 +8,7 @@ import { SidebarContext } from './sidebar/Sidebar' import AlbumSidebar from './sidebar/AlbumSidebar' import gql from 'graphql-tag' import { useLazyQuery } from '@apollo/react-hooks' +import { authToken } from '../authentication' const Header = styled.h1` margin: 24px 0 8px 0 !important; @@ -55,7 +56,7 @@ const AlbumTitle = ({ album, disableLink = false }) => { useEffect(() => { if (!album) return - if (localStorage.getItem('token') && disableLink == true) { + if (authToken() && disableLink == true) { fetchPath({ variables: { id: album.id, @@ -93,7 +94,7 @@ const AlbumTitle = ({ album, disableLink = false }) => {
{breadcrumbSections} {title} - {localStorage.getItem('token') && ( + {authToken() && ( { updateSidebar() diff --git a/ui/src/components/header/Header.js b/ui/src/components/header/Header.js index 4db37ef6..b7cb2a31 100644 --- a/ui/src/components/header/Header.js +++ b/ui/src/components/header/Header.js @@ -3,6 +3,7 @@ import styled from 'styled-components' import SearchBar from './Searchbar' import logoPath from '../../assets/photoview-logo.svg' +import { authToken } from '../../authentication' const Container = styled.div` height: 60px; @@ -40,7 +41,7 @@ const Header = () => ( Photoview - {localStorage.getItem('token') ? : null} + {authToken() ? : null} ) diff --git a/ui/src/components/messages/Messages.js b/ui/src/components/messages/Messages.js index a2f9bab2..60bbead6 100644 --- a/ui/src/components/messages/Messages.js +++ b/ui/src/components/messages/Messages.js @@ -2,6 +2,7 @@ import React, { useState, useEffect } from 'react' import { useTransition, animated } from 'react-spring' import styled from 'styled-components' import { Message } from 'semantic-ui-react' +import { authToken } from '../../authentication' import MessageProgress from './MessageProgress' import SubscriptionsHook from './SubscriptionsHook' @@ -124,7 +125,7 @@ const Messages = () => { ) })} - {localStorage.getItem('token') && ( + {authToken() && ( )} diff --git a/ui/src/components/messages/SubscriptionsHook.js b/ui/src/components/messages/SubscriptionsHook.js index f37670d4..e5f54e41 100644 --- a/ui/src/components/messages/SubscriptionsHook.js +++ b/ui/src/components/messages/SubscriptionsHook.js @@ -2,6 +2,7 @@ import React, { useState, useEffect } from 'react' import PropTypes from 'prop-types' import { useSubscription } from 'react-apollo' import gql from 'graphql-tag' +import { authToken } from '../../authentication' const notificationSubscription = gql` subscription notificationSubscription { @@ -21,7 +22,7 @@ const notificationSubscription = gql` let messageTimeoutHandles = new Map() const SubscriptionsHook = ({ messages, setMessages }) => { - if (!localStorage.getItem('token')) { + if (!authToken()) { return null } diff --git a/ui/src/components/photoGallery/ProtectedImage.js b/ui/src/components/photoGallery/ProtectedImage.js index bf2b6e93..a9194a8d 100644 --- a/ui/src/components/photoGallery/ProtectedImage.js +++ b/ui/src/components/photoGallery/ProtectedImage.js @@ -1,91 +1,91 @@ import React, { useEffect, useState } from 'react' import PropTypes from 'prop-types' -let imageCache = {} +// let imageCache = {} -export async function fetchProtectedImage( - src, - { signal, headers: customHeaders } = { signal: null, headers: null } -) { - if (src) { - if (imageCache[src]) { - return imageCache[src] - } +// export async function fetchProtectedImage( +// src, +// { signal, headers: customHeaders } = { signal: null, headers: null } +// ) { +// if (src) { +// if (imageCache[src]) { +// return imageCache[src] +// } - let headers = { - ...customHeaders, - } - if (localStorage.getItem('token')) { - headers['Authorization'] = `Bearer ${localStorage.getItem('token')}` - } +// let headers = { +// ...customHeaders, +// } +// if (localStorage.getItem('token')) { +// headers['Authorization'] = `Bearer ${localStorage.getItem('token')}` +// } - let image = await fetch(src, { - headers, - signal, - }) +// let image = await fetch(src, { +// headers, +// signal, +// }) - image = await image.blob() - const url = URL.createObjectURL(image) +// image = await image.blob() +// const url = URL.createObjectURL(image) - // eslint-disable-next-line require-atomic-updates - imageCache[src] = url +// // eslint-disable-next-line require-atomic-updates +// imageCache[src] = url - return url - } -} +// return url +// } +// } /** * An image that needs a authorization header to load */ const ProtectedImage = ({ src, ...props }) => { - const [imgSrc, setImgSrc] = useState(null) + // const [imgSrc, setImgSrc] = useState(null) - useEffect(() => { - if (imageCache[src]) return + // useEffect(() => { + // if (imageCache[src]) return - const fetchController = new AbortController() - let canceled = false + // const fetchController = new AbortController() + // let canceled = false - setImgSrc('') + // setImgSrc('') - const imgUrl = new URL(src) - const fetchHeaders = {} + // const imgUrl = new URL(src) + // const fetchHeaders = {} - if (localStorage.getItem('token') == null) { - // Get share token if not authorized + // if (localStorage.getItem('token') == null) { + // // Get share token if not authorized - const tokenRegex = location.pathname.match(/^\/share\/([\d\w]+)(\/?.*)$/) - if (tokenRegex) { - const token = tokenRegex[1] - imgUrl.searchParams.set('token', token) + // const tokenRegex = location.pathname.match(/^\/share\/([\d\w]+)(\/?.*)$/) + // if (tokenRegex) { + // const token = tokenRegex[1] + // imgUrl.searchParams.set('token', token) - const tokenPassword = sessionStorage.getItem(`share-token-pw-${token}`) - if (tokenPassword) { - fetchHeaders['TokenPassword'] = tokenPassword - } - } - } + // const tokenPassword = sessionStorage.getItem(`share-token-pw-${token}`) + // if (tokenPassword) { + // fetchHeaders['TokenPassword'] = tokenPassword + // } + // } + // } - fetchProtectedImage(imgUrl.href, { - signal: fetchController.signal, - headers: fetchHeaders, - }) - .then(newSrc => { - if (!canceled) { - setImgSrc(newSrc) - } - }) - .catch(error => { - console.log('Fetch image error', error.message) - }) + // fetchProtectedImage(imgUrl.href, { + // signal: fetchController.signal, + // headers: fetchHeaders, + // }) + // .then(newSrc => { + // if (!canceled) { + // setImgSrc(newSrc) + // } + // }) + // .catch(error => { + // console.log('Fetch image error', error.message) + // }) - return function cleanup() { - canceled = true - fetchController.abort() - } - }, [src]) + // return function cleanup() { + // canceled = true + // fetchController.abort() + // } + // }, [src]) - return + return } ProtectedImage.propTypes = { diff --git a/ui/src/components/photoGallery/presentView/PresentMedia.js b/ui/src/components/photoGallery/presentView/PresentMedia.js index e1947c55..4fa55e20 100644 --- a/ui/src/components/photoGallery/presentView/PresentMedia.js +++ b/ui/src/components/photoGallery/presentView/PresentMedia.js @@ -41,7 +41,12 @@ const PresentMedia = ({ media, imageLoaded, ...otherProps }) => { if (media.type == 'video') { return (
- +
diff --git a/ui/src/components/sidebar/MediaSidebar.js b/ui/src/components/sidebar/MediaSidebar.js index de9e1193..da44bbeb 100644 --- a/ui/src/components/sidebar/MediaSidebar.js +++ b/ui/src/components/sidebar/MediaSidebar.js @@ -7,6 +7,7 @@ import SidebarItem from './SidebarItem' import ProtectedImage from '../photoGallery/ProtectedImage' import SidebarShare from './Sharing' import SidebarDownload from './SidebarDownload' +import { authToken } from '../../authentication' const mediaQuery = gql` query sidebarPhoto($id: Int!) { @@ -87,7 +88,12 @@ const PreviewMedia = ({ media, previewImage }) => { if (media.type == 'video') { return ( - + ) @@ -225,7 +231,7 @@ const MediaSidebar = ({ media, hidePreview }) => { const [loadMedia, { loading, error, data }] = useLazyQuery(mediaQuery) useEffect(() => { - if (media != null && localStorage.getItem('token')) { + if (media != null && authToken()) { loadMedia({ variables: { id: media.id, @@ -236,7 +242,7 @@ const MediaSidebar = ({ media, hidePreview }) => { if (!media) return null - if (!localStorage.getItem('token')) { + if (!authToken()) { return } diff --git a/ui/src/components/sidebar/Sharing.js b/ui/src/components/sidebar/Sharing.js index a36541e8..3b0793d2 100644 --- a/ui/src/components/sidebar/Sharing.js +++ b/ui/src/components/sidebar/Sharing.js @@ -11,6 +11,7 @@ import { Icon, } from 'semantic-ui-react' import copy from 'copy-to-clipboard' +import { authToken } from '../../authentication' const sharePhotoQuery = gql` query sidbarGetPhotoShares($id: Int!) { @@ -218,7 +219,7 @@ ShareItemMoreDropdown.propTypes = { const SidebarShare = ({ photo, album }) => { if ((!photo || !photo.id) && (!album || !album.id)) return null - if (!localStorage.getItem('token')) return null + if (!authToken()) return null const isPhoto = !!photo const id = isPhoto ? photo.id : album.id diff --git a/ui/src/components/sidebar/SidebarDownload.js b/ui/src/components/sidebar/SidebarDownload.js index 406e8202..71ce882e 100644 --- a/ui/src/components/sidebar/SidebarDownload.js +++ b/ui/src/components/sidebar/SidebarDownload.js @@ -6,6 +6,7 @@ import { MessageState } from '../messages/Messages' import { useLazyQuery } from 'react-apollo' import gql from 'graphql-tag' import download from 'downloadjs' +import { authToken } from '../../authentication' const downloadQuery = gql` query sidebarDownloadQuery($mediaId: Int!) { @@ -30,22 +31,22 @@ function formatBytes(bytes) { const downloadPhoto = async url => { const imgUrl = new URL(url) - let headers = { - Authorization: `Bearer ${localStorage.getItem('token')}`, - } + // let headers = { + // Authorization: `Bearer ${localStorage.getItem('token')}`, + // } - if (localStorage.getItem('token') == null) { + if (authToken() == null) { // Get share token if not authorized const token = location.pathname.match(/^\/share\/([\d\w]+)(\/?.*)$/) if (token) { imgUrl.searchParams.set('token', token[1]) } - headers = {} + // headers = {} } const response = await fetch(imgUrl.href, { - headers, + // headers, }) const totalBytes = Number(response.headers.get('content-length'))