diff --git a/.gitignore b/.gitignore index 21c6a18..5beeaec 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ .vscode +.Key.js agent/node_modules diff --git a/AuctionServices/Scraper/Drouot/Drouot.js b/AuctionServices/Scraper/Drouot/Drouot.js index fab92e7..7e9f418 100644 --- a/AuctionServices/Scraper/Drouot/Drouot.js +++ b/AuctionServices/Scraper/Drouot/Drouot.js @@ -1,5 +1,6 @@ // Interencheres.js 'use strict'; +const { config } = require('../../../config'); const {Scraper} = require('../Scraper'); const DrouotData = require('./DrouotData'); @@ -131,6 +132,8 @@ class Drouot extends Scraper { // askStop : sale is followed by the AuctionAgent and the user ask to stop following // pause : the Sale is stopped by the Auction House and ready to restart // end : the Sale is ended + // endOnError : the Sale is ended on error + // endOnRequest: end of follow asked by user let status = 'ready' @@ -258,6 +261,9 @@ class Drouot extends Scraper { page = await this.CheckAndConnect(page); + let lastbid = 0; + let CloseCount = 0; + //init Protobuf Decoder const protobuf = require("protobufjs"); const root = await protobuf.load(this._PATH_PROTOBUF_FILE); @@ -278,7 +284,6 @@ class Drouot extends Scraper { if(BideMessage.vente && BideMessage.vente.lot && BideMessage.vente.lot.lotId != undefined){ DataLot = await this.platformData.getLiveDataLot(BideMessage.vente.lot.lotId); } - //console.log('BideMessage Type: '+BideMessage.type+' Lot: '+BideMessage.vente.lot.lotId); switch (BideMessage.type) { case 'PING': @@ -287,16 +292,31 @@ class Drouot extends Scraper { break; case 'INIT': console.log('INIT'); - break; - case 'CLOSE': + + case 'CLOSE': console.log('CLOSE'); + //refresh the live to avoid unintoended close + clearInterval(CheckAskStop); + CloseCount++; + + if(CloseCount > config.agent.maxCloseWebsockets){ + console.log('CloseCount > config.agent.maxCloseWebsockets') + StopLive('endOnError') + return + }else{ + console.log('Retry #'+CloseCount) + await GoLive(); + } + break; case 'BID': console.log('BID'); console.log('Lot: '+BideMessage.vente.lot.lotId+' Amount: '+BideMessage.vente.bid.amount); - + + lastbid = Date.now(); + await this.JucundusBid( BideMessage.vente.lot.lotId, Date.now(), @@ -392,61 +412,91 @@ class Drouot extends Scraper { //console.log('Unknown type:', BideMessage); } - }; + }; + + let CheckAskStop = null; + let CheckLastBid = null; + let Socket = null; + + // Stop the Live + const StopLive = async (code) => { + clearInterval(CheckAskStop); + clearInterval(CheckLastBid); + await this.JucundusEndSale(code) + + page.close() + browser.close() + } + + return + // create the live URL let {saleID} = await this.platformData.getUrlInfo(this.Url); let UrlLive = this._PAGE_MAIN + "live/bidlive/" + saleID; - let CheckAskStop = null; - let Socket = null; - - // Stop the Live - const StopLive = async (params) => { - clearInterval(CheckAskStop); - page.close() - browser.close() + const GoLive = async () => { + try{ + console.log('UrlLive : '+UrlLive) + + await page.goto(UrlLive, { waitUntil: 'domcontentloaded' }); + + // intercept Lots Data + await page.route('https://api.drouot.com/drouot/gingolem/api/live/venteInfos/'+saleID+'?lang=fr', async route => { + console.log('GetLiveData') + const response = await route.fetch(); + const LotData = await response.json(); + this.platformData.setLiveData(LotData.data); + route.continue(); + }); + + page.on('websocket', ws => { + Socket = ws; + Socket.on('framereceived', listener); + console.log('Websocket connected'); + }); + + console.log('UrlLive : reload') + await page.reload(); + + // check if stop was asked + CheckAskStop = setInterval(async () => { + this.JucundusCheckStop() + .then(async AskStop => { + if(AskStop){ + await StopLive('endOnRequest') + return + } + }) + }, 10000); // 10000 milliseconds = 10 seconds + + // Check every minute if the last event is more than 10 minutes ago + CheckLastBid = setInterval(() => { + if (lastbid && Date.now() - lastbid > 10 * 60 * 1000) { + console.log("More than 10 minutes since the last bid."); + this.JucundusSetSaleStatus(saleInfo, 'end') + (async () => { + await StopLive('end'); + })(); + return + } + }, 60 * 1000); // 60 seconds = 1 minute + + }catch(e){ + console.log('Error : '+e) + throw new Error('Error: '+e) + } + } - try{ - console.log('UrlLive : '+UrlLive) + await GoLive(); - await page.goto(UrlLive, { waitUntil: 'domcontentloaded' }); - - // intercept Lots Data - await page.route('https://api.drouot.com/drouot/gingolem/api/live/venteInfos/'+saleID+'?lang=fr', async route => { - console.log('GetLiveData') - const response = await route.fetch(); - const LotData = await response.json(); - this.platformData.setLiveData(LotData.data); - route.continue(); - }); + } - page.on('websocket', ws => { - Socket = ws; - Socket.on('framereceived', listener); - console.log('Websocket connected'); - }); - - console.log('UrlLive : reload') - await page.reload(); - - // check if stop was asked - CheckAskStop = setInterval(async () => { - this.JucundusCheckStop() - .then(AskStop => { - if(AskStop){ - StopLive() - } - }) - }, 10000); // 10000 milliseconds = 10 seconds - - }catch(e){ - console.log('Error : '+e) - throw new Error('Error: '+e) - } + CaptureVideo = async () => { } }; + module.exports = Drouot \ No newline at end of file diff --git a/AuctionServices/Scraper/Drouot/DrouotData.js b/AuctionServices/Scraper/Drouot/DrouotData.js index 26be1e1..a92d7c7 100644 --- a/AuctionServices/Scraper/Drouot/DrouotData.js +++ b/AuctionServices/Scraper/Drouot/DrouotData.js @@ -344,9 +344,35 @@ class DrouotData extends ScraperTools { SaleDateString = SaleDateString.trim() let cleanStr = SaleDateString.replace(/\\s|\\n/g, ' ').replace(/\s+/g, ' '); - - SaleDate = moment.tz(cleanStr, 'dddd D MMMM à HH:mm (z)', 'fr', 'Europe/Paris').format(); + // Extract the timezone abbreviation + const timezoneAbbrMatch = cleanStr.match(/\(([^)]+)\)$/); + let timezoneAbbr = timezoneAbbrMatch ? timezoneAbbrMatch[1] : null; + + // Map of common timezone abbreviations to full timezone names + const timezoneMap = { + 'BST': 'Europe/London', + 'CET': 'Europe/Paris', + 'CEST': 'Europe/Paris', + 'EDT': 'America/New_York', + 'EST': 'America/New_York', + 'PST': 'America/Los_Angeles', + 'CDT': 'America/Chicago', + // Add more as needed + }; + // Replace the abbreviation with the full timezone name if it exists in the map + if (timezoneAbbr && timezoneMap[timezoneAbbr]) { + cleanStr = cleanStr.replace(`(${timezoneAbbr})`, timezoneMap[timezoneAbbr]); + } + + console.log('cleanStr : '+cleanStr) + + // Parse the date string with the correct format and timezone + let saleDate = moment.tz(cleanStr, 'dddd D MMMM à HH:mm z', 'fr', timezoneMap[timezoneAbbr] || 'UTC'); + + // Convert to the desired timezone "Europe/Paris" + SaleDate = saleDate.tz('Europe/Paris').format(); + // Live Sale }else{ SaleDate = moment.tz('Europe/Paris').format(); diff --git a/AuctionServices/Scraper/Interencheres/Interencheres.js b/AuctionServices/Scraper/Interencheres/Interencheres.js index 795134c..b1f7bc0 100644 --- a/AuctionServices/Scraper/Interencheres/Interencheres.js +++ b/AuctionServices/Scraper/Interencheres/Interencheres.js @@ -120,6 +120,8 @@ class Interencheres extends Scraper { // askStop : sale is followed by the AuctionAgent and the user ask to stop following // pause : the Sale is stopped by the Auction House and ready to restart // end : the Sale is ended + // endOnError : the Sale is ended on error + // endOnRequest: end of follow asked by user let status = 'ready' @@ -178,6 +180,7 @@ class Interencheres extends Scraper { const StopLive = async (params) => { clearInterval(CheckAskStop); //Socket.off('Network.webSocketFrameReceived', listener); + await this.JucundusEndSale('end') page.close() browser.close() } diff --git a/AuctionServices/Scraper/Scraper.js b/AuctionServices/Scraper/Scraper.js index c69981f..d390f65 100644 --- a/AuctionServices/Scraper/Scraper.js +++ b/AuctionServices/Scraper/Scraper.js @@ -2,6 +2,8 @@ 'use strict'; const fs = require('node:fs'); const fetch = require('node-fetch'); +const { config } = require('../../config'); +const { Key } = require('../../.Key'); class Scraper { @@ -13,18 +15,26 @@ class Scraper { _PWD = "" _PATH_SESSION_FILE = "" + _PATH_TOKEN_FILE = "" _BROWSER_TOOL = null _Proxy = "" _DebugMode = false - _JucundusUrl = "http://host.docker.internal:3000" + _JucundusUrl = "" + + token = "" constructor(Url) { this.Url = Url; + this._JucundusUrl = config.jucundus.url; + + this._PATH_TOKEN_FILE = ".session/token.json" + this.token = this.getTokenInCache(); } + async _getContext(browser) { return new Promise(async (resolve, reject) => { try { @@ -73,9 +83,146 @@ class Scraper { getLotList({ page, data}) {} - async Live({ page, data}) {} + getTokenInCache(){ + if (fs.existsSync(this._PATH_TOKEN_FILE)) { + let rawdata = fs.readFileSync(this._PATH_TOKEN_FILE); + let token = JSON.parse(rawdata); + return token.token; + } + return ""; + } + setTokenInCache(token){ + let data = JSON.stringify({token: token}); + fs.writeFileSync(this._PATH_TOKEN_FILE, data); + } + + isTokenExpired(token) { + try { + const payload = JSON.parse(atob(token.split('.')[1])); + if (!payload || !payload.exp) { + return true; + } + const currentTime = Math.floor(Date.now() / 1000); + return payload.exp < currentTime; + } catch (error) { + console.error('Error decoding token:', error); + return true; + } + } + + async isAgentConnected(){ + + return new Promise((resolve, reject) => { + + fetch(this._JucundusUrl+'/api/user/agentConnected',{ + method: 'GET', + headers: { + 'Authorization': 'Bearer '+this.token + } + }) + .then(response => { + if (!response.ok) { + console.log('isAgentConnected ? Agent not connected: '+response.statusText) + reject(false) + return; + } + console.log('isAgentConnected ? Agent connected') + resolve(true); + return; + }) + .catch(error => { + console.log('isAgentConnected ? error Agent not connected: '+error) + reject(false) + return; + }); + }); + } + + async checkJucundusConnexion(){ + + if(!this.token){ + console.log('No token') + return false + } + + if(this.isTokenExpired(this.token)){ + console.log('Token expired') + return false + } + + try { + const isConnected = await this.isAgentConnected(); + if (!isConnected) { + console.log('Agent not connected'); + return false; + } + } catch (error) { + console.log('Agent not connected'); + return false; + } + + return true; + + } + + async getNewToken(email, password) { + + try { + const response = await fetch(this._JucundusUrl+'/authenticate', { + method: 'POST', + headers: { + 'Content-Type': 'application/json' + }, + body: JSON.stringify({ email, password }) + }); + if (!response.ok) { + throw new Error('Failed to retrieve new token'); + } + const data = await response.json(); + this.setTokenInCache(data.token); + return data.token; + } catch (error) { + console.error('Error retrieving new token:', error); + throw error; + } +} + + async RequestJucundus(url, method, body = null){ + console.log('RequestJucundus() '+url) + if (!await this.checkJucundusConnexion()) { + this.token = await this.getNewToken(config.jucundus.useremail, Key.jucundusPassword); + } + + return new Promise((resolve, reject) => { + + fetch(url,{ + method: method, + headers: { + 'Authorization': 'Bearer '+this.token, + 'Content-Type': 'application/json' + }, + body: body + }) + .then(response => { + if (!response.ok) { + return response.json().then(err => { + throw new Error(err.error || 'Unknown error'); + }); + } + return response.json(); + }) + .then(data => { + console.log('RequestJucundus() data:' + JSON.stringify(data, null, 2)) + resolve(data); + }) + .catch(error => { + reject(error); + }); + }); + } + async JucundusCheckStop(){ //console.log('Check if Stop is asked') @@ -83,8 +230,7 @@ class Scraper { let url = encodeURIComponent(this.Url) return new Promise((resolve, reject) => { - fetch(this._JucundusUrl+'/api/sale/getByUrl/'+url) - .then(response => response.json()) + this.RequestJucundus(this._JucundusUrl+'/api/sale/getByUrl/'+url, 'GET') .then(saleInfo => { let status = saleInfo.status //console.log('status : '+status) @@ -93,34 +239,75 @@ class Scraper { console.log('Stop was asked') // return to ready status - this.JucundusSetSaleStatus(saleInfo, 'ready') + this.JucundusSetSaleStatus(saleInfo, 'end') .then( resolve(true) ); } else { resolve(false); - } + } }) .catch(error => { console.error(error); reject(new Error('Error: '+error)) }); }) + + + // return new Promise((resolve, reject) => { + // fetch(this._JucundusUrl+'/api/sale/getByUrl/'+url) + // .then(response => { + // if (!response.ok) { + // return response.json().then(err => { + // throw new Error(err.error || 'Unknown error'); + // }); + // } + // return response.json(); + // }) + // .then(saleInfo => { + // let status = saleInfo.status + // //console.log('status : '+status) + // if(status == 'askStop'){ + + // console.log('Stop was asked') + + // // return to ready status + // this.JucundusSetSaleStatus(saleInfo, 'end') + // .then( + // resolve(true) + // ); + + // } else { + // resolve(false); + // } + // }) + // .catch(error => { + // console.error(error); + // reject(new Error('Error: '+error)) + // }); + // }) } - async JucundusEndSale(){ - console.log('JucundusEndSale') - + async JucundusEndSale(code){ + console.log('JucundusEndSale: '+code) + // check if stop was asked let url = encodeURIComponent(this.Url) return new Promise((resolve, reject) => { - fetch(this._JucundusUrl+'/api/sale/getByUrl/'+url) - .then(response => response.json()) + // DEBUG + resolve(true) + + if(code != 'end' && code != 'endOnError' && code != 'endOnRequest'){ + console.error('Error: code must be end or endOnError or endOnRequest') + reject(new Error('Error: code must be end or endOnError or endOnRequest')) + } + + this.RequestJucundus(this._JucundusUrl+'/api/sale/getByUrl/'+url, 'GET') .then(saleInfo => { // set end status - this.JucundusSetSaleStatus(saleInfo, 'end') + this.JucundusSetSaleStatus(saleInfo, code) .then( resolve(true) ); @@ -133,13 +320,11 @@ class Scraper { } async JucundusSetSaleStatus(saleInfo, status){ + // change the status of the sale saleInfo.status = status return new Promise((resolve, reject) => { - fetch(this._JucundusUrl+'/api/sale/sale/'+saleInfo._id, { - method: 'PUT', - headers: {'Content-Type': 'application/json'}, - body: JSON.stringify(saleInfo)}) + this.RequestJucundus(this._JucundusUrl+'/api/sale/sale/'+saleInfo._id, 'PUT', JSON.stringify(saleInfo)) .then(resolve(true)) .catch(error => { console.error(error); @@ -149,13 +334,14 @@ class Scraper { } async JucunduNextItem(sale_id, timestamp, item_id, num_lot, title, description, EstimateLow, EstimateHigh, RawData){ + console.log('JucunduNextItem', sale_id, timestamp, item_id, num_lot) - return new Promise((resolve, reject) => { - fetch(this._JucundusUrl+'/api/lot/NextItem', { - method: 'POST', - headers: {'Content-Type': 'application/json'}, - body: JSON.stringify( + return new Promise((resolve, reject) => { + this.RequestJucundus( + this._JucundusUrl+'/api/lot/NextItem', + 'POST', + JSON.stringify( { idPlatform: item_id, idSalePlatform: sale_id, @@ -168,7 +354,7 @@ class Scraper { EstimateHigh: EstimateHigh, RawData: RawData } - )}) + )) .then(resolve(true)) .catch(error => { console.error(error); @@ -178,12 +364,13 @@ class Scraper { } async JucundusBid(item_id, timestamp, amount, auctioned_type){ + console.log('JucundusBid', timestamp, item_id, amount, auctioned_type) return new Promise((resolve, reject) => { - fetch(this._JucundusUrl+'/api/lot/Bid', { - method: 'POST', - headers: {'Content-Type': 'application/json'}, - body: JSON.stringify( + this.RequestJucundus( + this._JucundusUrl+'/api/lot/Bid', + 'POST', + JSON.stringify( { idPlatform: item_id, platform: this._Name, @@ -191,7 +378,7 @@ class Scraper { amount: amount, auctioned_type: auctioned_type } - )}) + )) .then(resolve(true)) .catch(error => { console.error(error); @@ -200,14 +387,14 @@ class Scraper { }) } - async JucunduAuctionedItem(item_id, timestamp, amount, sold, auctioned_type){ + async JucunduAuctionedItem(item_id, timestamp, amount, sold, auctioned_type){ console.log('JucunduAuctionedItem', timestamp, item_id, amount, sold) return new Promise((resolve, reject) => { - fetch(this._JucundusUrl+'/api/lot/AuctionedItem', { - method: 'POST', - headers: {'Content-Type': 'application/json'}, - body: JSON.stringify( + this.RequestJucundus( + this._JucundusUrl+'/api/lot/AuctionedItem', + 'POST', + JSON.stringify( { idPlatform: item_id, platform: this._Name, @@ -216,7 +403,7 @@ class Scraper { auctioned_type: auctioned_type, sold: sold, } - )}) + )) .then(resolve(true)) .catch(error => { console.error(error); diff --git a/agent/.session/session_drouot.json b/agent/.session/session_drouot.json index 18c8ef9..69095a8 100644 --- a/agent/.session/session_drouot.json +++ b/agent/.session/session_drouot.json @@ -10,26 +10,6 @@ "secure": false, "sameSite": "Lax" }, - { - "name": "JSESSIONID", - "value": "CEE9A69D532738CA6F448BC54BD5FA98", - "domain": "drouot.com", - "path": "/", - "expires": -1, - "httpOnly": true, - "secure": true, - "sameSite": "Lax" - }, - { - "name": "cf_clearance", - "value": "Nw88GFRRH4A.R3IrqBs1WHV3v2j6b72TL4xFNt1qtRY-1716455904-1.0.1.1-YiA2MwdTbDytd5SaxdOm_F7ru5Q5bW.MaPs1FxJrr7YtILq0z0u9a4Lghyt2DIaNM_b_2hbki5IKioTVnUlqkQ", - "domain": ".drouot.com", - "path": "/", - "expires": 1747991903.778234, - "httpOnly": true, - "secure": true, - "sameSite": "None" - }, { "name": "consentLevel", "value": "none", @@ -41,33 +21,96 @@ "sameSite": "Lax" }, { - "name": "aws.auth.refresh", - "value": "eyJjdHkiOiJKV1QiLCJlbmMiOiJBMjU2R0NNIiwiYWxnIjoiUlNBLU9BRVAifQ.ej0FDIw3VwTFabbv_Xrthwn6QRxOrGSlTP8P-hM3xyDmhigcIepCgEUlgjSO-taBevdDgiDNuRZ2ymbsmSHjBTgtPPhBJMlNW1CJMFpf34cnHp8P8fNso7KVZH98CVT8a-klxeNUw8sJbzV76E2pefGPiKahMbgNcct6I4C0lmK60569b1ADgDJUXoZ3ZWLM5h7dmu2_zEwcu3rcJSAZvqLBQBrBhw1ck2tivoMVl0Rp3rRDmYCkbvjYpVxozv_KCBA1pKdm_n1E78T4nlJR12UVZKwGj4TnM3_AiV43J-FUKkj-rDEoPfJrWlZh0J3aV403sDGeO_R7C8zOvMz8qQ.HTEsnaMZSmoB5bMT.CPMenx7Y1fkZnG3xdudDXwto0S9nXhlrviwGAUaEV0PdAiN1JRyWyfd2gfZ9gqDJ6CxBog-kZ45nttrdY2JjS71HgBfrg3RAqRqUyiRd9OLUTtHXgysdf6tXGZYqm2j62uTzq5aYWwr_KUMEYKqH45TrxAEnBGlCaKX5ielLghK6ZA_EWrOK3oJW3aM_-mZKD0vrJd9_iwVAUMKk_hdCF1UFqsuVHXZqXxQ_iOPzyd_t5Ui_2WgVqqLZTteAsFwr_L_TqpoM11AgSH-8a1ad05JwCdeMxyhZnW8Gf172Yt7pVzUFuV491KAxXdsgxCbFIhReYhOqABCsS9fKKbi6VBDtDBrRqGeiHgfOapVMLeg8-Va-_YGa1_4oRbX_zye_HTz3WE-xmBBwt98PVEJp4pWr2lY7wDgisqzLgI8foWm1YVWFD5rypAsJxEu-9-25SVErMVlptRaZ650YFHWNrkEr3oeqzwriIxMEjm92gxgVPQOO0Q5gqj9WcUHrbeq01xr6WBhX84AqGqTpT-kxbSrFBxHFMM3zhPey4ElJ2unc_ppj2r96e3FNjTmhRdhYYz827oewmJZZwhAF2KI8a_MEz6-W18b5ju0teM4lWBWRedq8IMeTFuEZ8-nlkQTiDnsSFXqZNtFVfJGcbKKTX8LCm708DrG5QGvqjycOkXrrnw-OCaUibCWbymJzwYdPD1sLLhitMpgI6pKW8H74K7bIb_v2IeMo3hH9gm2n6SI120EpD7n74UCIGx1fn5CB28neuj-_BegrcZNd6KEs0iPEhNOpHKd7k_G8riKX-ZtKIQcqZ8MtwAvjWVVFELEkpXR2IwfW2jXzBObIvcDYYNVijroFUZ-8oObp0dAIaUFtoByIzw3VOzOc4qbCSyelFC1YyoZJgbNW2ic6ZvL8pdzYTogjI_XHakVLBk8jeRg95SXtz9XzpLyx_ZoTX5LzEh5T897tOePl1NmIptU17IiBuwxFj_nYoVgDYbbGz1ox9vEWdrAE6EpfzhFrxWVMijyfjyauWaixri-harPAbhirrGG7QEeURqv0LCMMy1w3LyaZ9p9saG3DzX0yzrERgXMNvbFi4OYY3Cb0O8bo0kjHVY7a6Yj_qKKpfIKGclRKmndxkLK5A6JJkqy4fSLK-v9RbpWUiTC-_0L2k9lEGiK5rgPhMSRhyI5XYUW1rbB_XEKPU12M5uxER0NvjomXgTUy0yOdbDfpIYb89Bs2BK-SE0MAJSepzC8bsW4CWOnfCWGnuOGQphRfCuxAIkvd-4Lwm-Nyt8-Mmvh5VhQw79v8mx2eZNzk4DyiTDbSQUwdoCoEpgyoQnvnxObYVxXUeixB.LW8iCOUVXGCbeHw2rTF6Uw", + "name": "JSESSIONID", + "value": "F6EE192A727F489C38F2DB477FC1A27D", + "domain": "drouot.com", + "path": "/", + "expires": -1, + "httpOnly": true, + "secure": true, + "sameSite": "Lax" + }, + { + "name": "sbss_e51870e9-89ed-4337-872e-e48073010805", + "value": "70066e04-417d-4157-ab37-5b19f86e2bae", + "domain": "site-azp.slgnt.eu", + "path": "/", + "expires": 1752310289.04592, + "httpOnly": true, + "secure": true, + "sameSite": "None" + }, + { + "name": "sbt_i", + "value": "7ZmU0ZTAyMGUtMDY0YS00ODJlLTk4YjAtODQyZTEyZTVkOWNhOzNzAwNjZlMDQtNDE3ZC00MTU3LWFiMzctNWIxOWY4NmUyYmFlOzsA=", "domain": ".drouot.com", "path": "/", - "expires": 1718955905.860105, + "expires": 1752310289, + "httpOnly": false, + "secure": false, + "sameSite": "Lax" + }, + { + "name": "sbt_p", + "value": "H4sIAAAAAAAAAwGcAmP9/////x+LCAAAAAAAAAPtVstu00AUdYpUaCkLWMCylhrRlZETnJeEhNxkjCJIXdwUiLqo4mQiBaVx5aQUFkhFsIEVQohP4Ce6Cb+ABCskdpW64RfAQ31tZzxOL48uEDnSOOOZO8fnjO/4ZllKF1Q1n6eqpmiZQtu75ApK075eUHJ2ptQp5mnWbtK06kMRXACfDpfev05JEvyeABbBL+GXRlnm/PvLS/H4lBQ2GLuy7djdXpe68lXZsR/S4UBuLzfdoSTt3/ydOMClsl4nt0yrsbVC9I0HulVfH5PL68A857hFWCppnMnzLafXo61h1+kPeMGT5gAXAzM1c6V6p0oslBeeOqbflXH6Z9td1+Ph5SUMAy7ULd0wquV1c8MqE5TiCGNM7AApdmanxSsSDAHmK+RetUzqjTWcQp8qpm6YoC4gjEJ07M5axCAW92ah8wjp/UzH7fJORWOAuYreMI37hNxGmQeqmPs9pL5zHcelfcfp84ISJwKla94RNg1PL0rpGF9M7mOk3AXP71aSsomTgIWaWSOrdcQeA473+I8tPkFanG+7zq4zvNZytnkPE6YAsxWzpldXUXo5ujHFsC7doRpVsypV1LzWVLRiliqloq0qRS1LM1maa5daTRE5L0xUosZOXWqTH/ln8Nn3dsoO4DHTii4gn1b0aUWPQnQOpxV9WtEZ/tuKLklfFj/uHf7s7c/4JHffhtOBDVG5XnyGCBQhaRoU3GgkBMRYWPv2Jux/lSXpxUHI9PwAwxTysbX8p0SE7x7wzCH/Sf+CJiLyrtiSp5vYp7L28l3YP5K9+5GX9zA3wrkGvlcjnOAg+T/g438Vf3NXWdawDIIcZJnFGutDZgH3kR/H3gLbW9ZYH/Y2puEHt1WZzyMSAABay56MnAIAAM6uM7zWcrZ5DxOmALMVs6ZXV1F6OboxxbAu3aEaVbMqVdS81lS0YpYqpaKtKkUtSzNZmmuXWk0ROS9MVKLGTl1qkx/5Z/DZ93bKDuAx", + "domain": ".drouot.com", + "path": "/", + "expires": 1752310289, + "httpOnly": false, + "secure": false, + "sameSite": "Lax" + }, + { + "name": "cf_clearance", + "value": "wMZTGpFvQrXVc24EgBEh5Z_l07dq3n7E_GmmYYMM_Zg-1720774289-1.0.1.1-6kQTG9zdIWY9Ticp9YkIpsJlgtCDUnN9A4gIx5h.nMvWEqSMySuZZoJ5rAF1ts.QH.MzWJ8HzESZuBALJ_K9Cw", + "domain": ".drouot.com", + "path": "/", + "expires": 1752310289.605213, + "httpOnly": true, + "secure": true, + "sameSite": "None" + }, + { + "name": "aws.auth.refresh", + "value": "eyJjdHkiOiJKV1QiLCJlbmMiOiJBMjU2R0NNIiwiYWxnIjoiUlNBLU9BRVAifQ.imuPu0l2BWRSCp5Deo-kkfjqrbXvrMOC7aLb73FLvWMEbZ_8wYPMIYDBVxWXCOue9lBOYWmBZ-gYmOpFjuub48kr0YH2XmS0CWvAjVaFOd1SLtA1JqPNCjzOhr4HqHNzY2p1v-LlWVkZMb6yzSJCo2i69X_uMhjI7vkwF5JBRLPfnhgpbTtuAfShe2fxwFVF3wcnIGwxwf9Mewftjw0vYAnU25kcUALthY_7os1vXG10B0HLJFlfG8AA0AZgOWin7YEYtNCR0fyILwVQLLrwrN1Df9I6nw0BT82u37GAZSihBNUekCBmLRf_eLad4DACY5YTwywzQjfLWIv6by0SYQ.32xpzYSlssbruFav.hmnVMOwHMa4fnXFrO_Eu402cEKhzl-uS_62OC51WXTOrY0qSXAGSjQLUleR8Aznkugbt738kCq7wzHeOxydaKdBIJC-hYfI3T1sFFBWPkyEjAmLPy6FI2FeFdKzFrIEOsKYyEQ_7R8uOzarTXnBr0wHBKyKqRhAmZpUO9ytMS2HHNd39Ta8kwDtkA848k-3XQ1J3we0r5w177Kp8jgZv2lmItu17Z3Q8xZbZNuZwdG2pyDUTJpoQRdbrhBFfPi2x5Arm3tSbOCX3eF_TOnFA5EPfuJF_OQkzFN1FgnJcXwY63VKcy4EzR02njK6WLDzECekK7ly_hAk83Rcon7NSWj0R-QCmtJu92MIwQ1VwOpfKZSG9s8w9V4TcFaRM7y_1CS8sa6hMiM6j1mvWsEk1pu-MyqsV-nZi6HRqtbCXAgrzkQ0JyrqHM17pLwoMC-YzHFVkYO2x9JvszbNg85QVC50e7HKEpg8DEfoXz-i686zxOCjEBTIzHEEs4L7ZgHm9wjKUdC7iyGdMxr1DhO4VFWxUENYJrDgFoUyHFmZbiz6tUzxYwZfYhJP-jb1UKNNYXl477kgmcr5x4nM0ShSWnKLiPUOkeez2D9THXLdPFliXiGfbL126AJMsSS16oiW9DaSfq6mikjiuBZhhLEKboRbzBVAAFx55BjWKs_x7O9MMbHGFeX5AQAfkgTbFKy92sahH_MimP7JQn7yx-AQefJpiKHt4aVoLTs2c09ytEgBQkY7m-zaRKAwCIUIa3IG4N2SU8aU0rDgg9_QXG6WV2G7M6GxEMqjeBU_o3CqS-2XP5lyxF5abY4yoxtiMbngXG-YrPcxQqMWX0SaRZSIp5vwKfc8CoELs0kmpZpJ3pJLwSCdmfrKqp4_fAGvYWB0UpAsUN9IqvYDROkCZlJMCh5X0N5U01jxjSOQFYDpQrkNQ4lwt1VQeAphH5ohPD0XRq3xm7amsouF6D2B0cmZIRSKf6yR013jL85RmKMxXQTHyFHLo5QCoUjgTfl6QfO11W7RUcitXtuG3Dthyx3NQ9Y9kypdZ3qJBg-RjQdIhJPVOUvjTDzka81tnLK3TisSjKEg8NSPeA0F-gihIPz5R88rKAWT_BKa4ugEjGuEKMdccglXmcFxkGMq-AR87t5Wfa9Ft2F5OS9rZuunpLXsHGRcQRvx46zfW_AvV0FOAgHDJvJ3FdWiIfN9Zazi5NnM5E-ZCtg9mlWYpxTn3_gljob8pOgD_AVltpsRMvgSmV5g_NwJTAqp8vQGQMNEg-ZFb3UtG4hpbHFre0CxQQ3iXfMF8bla5APL90ABvAtZHQMcsTaiOAMkCnzUmTVIgqcM4D2vH.wyRM3-165fGB8NIdapX8iA", + "domain": ".drouot.com", + "path": "/", + "expires": 1723274291.075802, "httpOnly": false, "secure": true, "sameSite": "Lax" }, { "name": "aws.auth.id", - "value": "eyJraWQiOiJaTktsNEx3c1NcL0xyYVdwaGVtcHE4OWVLWk05eUtUemtUQW40ZlM2bXFtST0iLCJhbGciOiJSUzI1NiJ9.eyJzdWIiOiI1ODY0NWVjYS1mNDllLTQ1YTktOWI0ZC1lNTg0M2RhZWNjNWUiLCJlbWFpbF92ZXJpZmllZCI6dHJ1ZSwiaXNzIjoiaHR0cHM6XC9cL2NvZ25pdG8taWRwLmV1LWNlbnRyYWwtMS5hbWF6b25hd3MuY29tXC9ldS1jZW50cmFsLTFfWE5GWDNIMzE0IiwiY29nbml0bzp1c2VybmFtZSI6IjU4NjQ1ZWNhLWY0OWUtNDVhOS05YjRkLWU1ODQzZGFlY2M1ZSIsIm9yaWdpbl9qdGkiOiI2YjUxMTM2Mi1kYmMwLTQ3MDctYjA0Zi05YTVmNzQyZjM5YjAiLCJhdWQiOiI0amNsZG9ib2YycWJuc3NtN2YxMDdnbGlxOCIsImV2ZW50X2lkIjoiNDAwNGViODItNDg1Mi00OTk2LWFjMjctNWQ1MTBiMmI3NTJmIiwidG9rZW5fdXNlIjoiaWQiLCJhdXRoX3RpbWUiOjE3MTY0NTU5MDUsImV4cCI6MTcxNjQ1OTUwNiwiaWF0IjoxNzE2NDU1OTA2LCJjdXN0b206cGFzc19pZCI6IjczOTAzMCIsImp0aSI6IjZjZjhmYjFlLWU1YTgtNDBkNS04NzkzLTk2YmRjNmZjMDU0ZCIsImVtYWlsIjoianAucmFudUBjb2dpcC5kZSJ9.I6lc4Y-fKSQJ1Vd5Lu41fP6_XuG9yaedk1ZKlXy3iyYV17HVxbypjkdTkgy1vbTU-QdS2gHcp9Ynf90q-PxkMuJZ_IWIU3njhoKE7--U4OkIPf7wfsFKq2rZGcUEyM0DxuedpRYbjN0Xesd6DF8nqWs5WGzy1NZDbXVys3ji0h5Y9H00bX7oypI_2ihFkcpRUYRzv8wywjBYoD8Jc7eOwqzeHNUkbs8L4ON2OnPCNBkJ33HKfw5Prnf4DahiZ9h6Vz0I2CTG4uIjI7yy0PpmDXz81-4JHy9G8NV2rEWTKUvJu1TWsMB5tRH50Ho3TBAqhUafKr1VB9uLTRg3gezsHw", + "value": "eyJraWQiOiJaTktsNEx3c1NcL0xyYVdwaGVtcHE4OWVLWk05eUtUemtUQW40ZlM2bXFtST0iLCJhbGciOiJSUzI1NiJ9.eyJzdWIiOiI1ODY0NWVjYS1mNDllLTQ1YTktOWI0ZC1lNTg0M2RhZWNjNWUiLCJlbWFpbF92ZXJpZmllZCI6dHJ1ZSwiaXNzIjoiaHR0cHM6XC9cL2NvZ25pdG8taWRwLmV1LWNlbnRyYWwtMS5hbWF6b25hd3MuY29tXC9ldS1jZW50cmFsLTFfWE5GWDNIMzE0IiwiY29nbml0bzp1c2VybmFtZSI6IjU4NjQ1ZWNhLWY0OWUtNDVhOS05YjRkLWU1ODQzZGFlY2M1ZSIsIm9yaWdpbl9qdGkiOiJiOTZmZDY0Zi05MWEwLTRmMmMtYTk2OC1kYmRkNDcxMTY4ZDYiLCJhdWQiOiI0amNsZG9ib2YycWJuc3NtN2YxMDdnbGlxOCIsImV2ZW50X2lkIjoiZDU5ZWE4NWYtZjQ4ZC00MWE1LTlmOGItYWQ1Njk4N2FiYWJiIiwidG9rZW5fdXNlIjoiaWQiLCJhdXRoX3RpbWUiOjE3MjA3NzQyOTAsImV4cCI6MTcyMDc3Nzg5MSwiaWF0IjoxNzIwNzc0MjkxLCJjdXN0b206cGFzc19pZCI6IjczOTAzMCIsImp0aSI6IjIwYmQ0NDRkLTE1YWMtNDRiYi05NzliLTI4YjM1OTgxMjIzMiIsImVtYWlsIjoianAucmFudUBjb2dpcC5kZSJ9.DnFgUj9yehDb5Y3bTobAkm1S5Pa59GJBKOn65KVbiTA3ou_haxwRLNewchwHChyK6q8fZvmllXdPAnMdCcF44UAo7sYjGAJK9u47AMer3oi-luNtAZzC8Jt94KaBRMTJLC7s3fCIkcZcVBk9FoSRwfPxVjR-w4rT4TLcxJQNT4OqEk2UAoGhtU4KHDfGkj3zM7ttPaXYz3KgQ4vBlK5iJ8G8AtQuoR84V5ZIhRzVqNjjIPKxfsh6sgv2cYxw0ceZwHj0_3-FdtMsMa1JRamWy16hGULof-n84kmdlEsRefKDK_62t-gN1Ngi2wn37IFsfviaM3WC99K5HWUCATNSMg", "domain": ".drouot.com", "path": "/", - "expires": 1716459506.054849, + "expires": 1720777891.317947, "httpOnly": false, "secure": true, "sameSite": "Lax" } ], "origins": [ + { + "origin": "https://drouot.com", + "localStorage": [ + { + "name": "sbt_i", + "value": "7ZmU0ZTAyMGUtMDY0YS00ODJlLTk4YjAtODQyZTEyZTVkOWNhOzNzAwNjZlMDQtNDE3ZC00MTU3LWFiMzctNWIxOWY4NmUyYmFlOzsA=" + }, + { + "name": "sbt_p", + "value": "H4sIAAAAAAAAAwGcAmP9/////x+LCAAAAAAAAAPtVstu00AUdYpUaCkLWMCylhrRlZETnJeEhNxkjCJIXdwUiLqo4mQiBaVx5aQUFkhFsIEVQohP4Ce6Cb+ABCskdpW64RfAQ31tZzxOL48uEDnSOOOZO8fnjO/4ZllKF1Q1n6eqpmiZQtu75ApK075eUHJ2ptQp5mnWbtK06kMRXACfDpfev05JEvyeABbBL+GXRlnm/PvLS/H4lBQ2GLuy7djdXpe68lXZsR/S4UBuLzfdoSTt3/ydOMClsl4nt0yrsbVC9I0HulVfH5PL68A857hFWCppnMnzLafXo61h1+kPeMGT5gAXAzM1c6V6p0oslBeeOqbflXH6Z9td1+Ph5SUMAy7ULd0wquV1c8MqE5TiCGNM7AApdmanxSsSDAHmK+RetUzqjTWcQp8qpm6YoC4gjEJ07M5axCAW92ah8wjp/UzH7fJORWOAuYreMI37hNxGmQeqmPs9pL5zHcelfcfp84ISJwKla94RNg1PL0rpGF9M7mOk3AXP71aSsomTgIWaWSOrdcQeA473+I8tPkFanG+7zq4zvNZytnkPE6YAsxWzpldXUXo5ujHFsC7doRpVsypV1LzWVLRiliqloq0qRS1LM1maa5daTRE5L0xUosZOXWqTH/ln8Nn3dsoO4DHTii4gn1b0aUWPQnQOpxV9WtEZ/tuKLklfFj/uHf7s7c/4JHffhtOBDVG5XnyGCBQhaRoU3GgkBMRYWPv2Jux/lSXpxUHI9PwAwxTysbX8p0SE7x7wzCH/Sf+CJiLyrtiSp5vYp7L28l3YP5K9+5GX9zA3wrkGvlcjnOAg+T/g438Vf3NXWdawDIIcZJnFGutDZgH3kR/H3gLbW9ZYH/Y2puEHt1WZzyMSAABay56MnAIAAM6uM7zWcrZ5DxOmALMVs6ZXV1F6OboxxbAu3aEaVbMqVdS81lS0YpYqpaKtKkUtSzNZmmuXWk0ROS9MVKLGTl1qkx/5Z/DZ93bKDuAx" + } + ] + }, { "origin": "https://auth.drouot.com", "localStorage": [ { "name": "CognitoIdentityServiceProvider.4jcldobof2qbnssm7f107gliq8.58645eca-f49e-45a9-9b4d-e5843daecc5e.accessToken", - "value": "eyJraWQiOiJYSTd2ejJDRW9pRVwvTnR0UGNkOEY0NE5QSDhHMzMzclJQRVB3OFFwRlJJRT0iLCJhbGciOiJSUzI1NiJ9.eyJzdWIiOiI1ODY0NWVjYS1mNDllLTQ1YTktOWI0ZC1lNTg0M2RhZWNjNWUiLCJpc3MiOiJodHRwczpcL1wvY29nbml0by1pZHAuZXUtY2VudHJhbC0xLmFtYXpvbmF3cy5jb21cL2V1LWNlbnRyYWwtMV9YTkZYM0gzMTQiLCJjbGllbnRfaWQiOiI0amNsZG9ib2YycWJuc3NtN2YxMDdnbGlxOCIsIm9yaWdpbl9qdGkiOiI2YjUxMTM2Mi1kYmMwLTQ3MDctYjA0Zi05YTVmNzQyZjM5YjAiLCJldmVudF9pZCI6IjQwMDRlYjgyLTQ4NTItNDk5Ni1hYzI3LTVkNTEwYjJiNzUyZiIsInRva2VuX3VzZSI6ImFjY2VzcyIsInNjb3BlIjoiYXdzLmNvZ25pdG8uc2lnbmluLnVzZXIuYWRtaW4iLCJhdXRoX3RpbWUiOjE3MTY0NTU5MDUsImV4cCI6MTcxNjQ1OTUwNiwiaWF0IjoxNzE2NDU1OTA2LCJqdGkiOiJkOGViNmNlNS00ZTE3LTRiZmQtYWVkNy01MjBmNzZlOGU2NGYiLCJ1c2VybmFtZSI6IjU4NjQ1ZWNhLWY0OWUtNDVhOS05YjRkLWU1ODQzZGFlY2M1ZSJ9.ltgmmPsITav_sGRrsc7AJz7GzViEGpWc_0qly3dVkZPZfL_NpDxIEz0_-XaikQd_Al_WYZ_k5yvh3DeDJzM4TiBFVVQDPydBb3IkeEj0x7djK_Yj5JUXM-SxaDIrtCkzXhxrwt_SCa0wkeKoPGfHSDt75-NYo4LXeZ15tntnsox-RoasVEop4HXBejWsfOiBsqptd4N8vCrK67nxiuNHTWZYylUz72iwMxtgwSvMVVNVV3FzU2N-puM8QvHhZQ96tCq0-jwTBVwR-DRdHL7IwbStze3-c53LFxbBmreXKn4aGiQybTEEwpDASeU0-YOl-Hgw4BD9gyOv2ECbINeiGw" + "value": "eyJraWQiOiJYSTd2ejJDRW9pRVwvTnR0UGNkOEY0NE5QSDhHMzMzclJQRVB3OFFwRlJJRT0iLCJhbGciOiJSUzI1NiJ9.eyJzdWIiOiI1ODY0NWVjYS1mNDllLTQ1YTktOWI0ZC1lNTg0M2RhZWNjNWUiLCJpc3MiOiJodHRwczpcL1wvY29nbml0by1pZHAuZXUtY2VudHJhbC0xLmFtYXpvbmF3cy5jb21cL2V1LWNlbnRyYWwtMV9YTkZYM0gzMTQiLCJjbGllbnRfaWQiOiI0amNsZG9ib2YycWJuc3NtN2YxMDdnbGlxOCIsIm9yaWdpbl9qdGkiOiJiOTZmZDY0Zi05MWEwLTRmMmMtYTk2OC1kYmRkNDcxMTY4ZDYiLCJldmVudF9pZCI6ImQ1OWVhODVmLWY0OGQtNDFhNS05ZjhiLWFkNTY5ODdhYmFiYiIsInRva2VuX3VzZSI6ImFjY2VzcyIsInNjb3BlIjoiYXdzLmNvZ25pdG8uc2lnbmluLnVzZXIuYWRtaW4iLCJhdXRoX3RpbWUiOjE3MjA3NzQyOTAsImV4cCI6MTcyMDc3Nzg5MSwiaWF0IjoxNzIwNzc0MjkxLCJqdGkiOiJjMThlYjZjMi0yMGUyLTRmNmUtOWExMi02ZmM4NmVhMGE0ODgiLCJ1c2VybmFtZSI6IjU4NjQ1ZWNhLWY0OWUtNDVhOS05YjRkLWU1ODQzZGFlY2M1ZSJ9.AbzC8YGLJqrMxcXYxbCW8XNMEQSZh-hgeWrfr7l-TdZ5aRa_M-U1ZffZWQtkotMuy1C6mBlItxFDTTt5iO2N0ijUzER3BVfIqZG_xzGf74eNcS64Y64mrSw2U5MLAhmXaLNFlbjhBj9IYyOUMZJE0RexIQByXzo0Yh72XUMWJKP1IEMgGlO-KqY3hoEnD7KJrgu0VMgOzvrITQ4dizeux-v8McEG79MKwyl810H_x0GzY_-L9LfTIZ_IfOHg6OuHnY-nfg5EY7NyvVEvNwZsuH7yjjLYIm2hcrryN0p_obwMYos6NDuo8NQNyP0iDTZeviQsR1iRp9Jtsh4w1pj0Sw" }, { "name": "persist:root", @@ -75,7 +118,7 @@ }, { "name": "CognitoIdentityServiceProvider.4jcldobof2qbnssm7f107gliq8.58645eca-f49e-45a9-9b4d-e5843daecc5e.clockDrift", - "value": "-1" + "value": "0" }, { "name": "amplify-signin-with-hostedUI", @@ -91,11 +134,11 @@ }, { "name": "CognitoIdentityServiceProvider.4jcldobof2qbnssm7f107gliq8.58645eca-f49e-45a9-9b4d-e5843daecc5e.idToken", - "value": "eyJraWQiOiJaTktsNEx3c1NcL0xyYVdwaGVtcHE4OWVLWk05eUtUemtUQW40ZlM2bXFtST0iLCJhbGciOiJSUzI1NiJ9.eyJzdWIiOiI1ODY0NWVjYS1mNDllLTQ1YTktOWI0ZC1lNTg0M2RhZWNjNWUiLCJlbWFpbF92ZXJpZmllZCI6dHJ1ZSwiaXNzIjoiaHR0cHM6XC9cL2NvZ25pdG8taWRwLmV1LWNlbnRyYWwtMS5hbWF6b25hd3MuY29tXC9ldS1jZW50cmFsLTFfWE5GWDNIMzE0IiwiY29nbml0bzp1c2VybmFtZSI6IjU4NjQ1ZWNhLWY0OWUtNDVhOS05YjRkLWU1ODQzZGFlY2M1ZSIsIm9yaWdpbl9qdGkiOiI2YjUxMTM2Mi1kYmMwLTQ3MDctYjA0Zi05YTVmNzQyZjM5YjAiLCJhdWQiOiI0amNsZG9ib2YycWJuc3NtN2YxMDdnbGlxOCIsImV2ZW50X2lkIjoiNDAwNGViODItNDg1Mi00OTk2LWFjMjctNWQ1MTBiMmI3NTJmIiwidG9rZW5fdXNlIjoiaWQiLCJhdXRoX3RpbWUiOjE3MTY0NTU5MDUsImV4cCI6MTcxNjQ1OTUwNiwiaWF0IjoxNzE2NDU1OTA2LCJjdXN0b206cGFzc19pZCI6IjczOTAzMCIsImp0aSI6ImIwNDEyYTBmLTZiN2UtNDc1YS04NTAyLTU0YmY5ODU5MzkxMiIsImVtYWlsIjoianAucmFudUBjb2dpcC5kZSJ9.Qfnv42vNIezdxohbyA1rF_ebfjeqx-LReTDOsYyWxwXdJC7yceu2P84Chr0DvZ0bo2dVtvgsL4TAV1pwFNjqMr5xSzcFNwDF-MzgBRtRWQ6R5OnHN1IX0zUFP9qZkuhaJMCz2kId84C_1YaXhDKqrK_qcvQ_-W1J11yfEbS4kVVZXf70Ko2eAq4XnTjtnTWURjEHM7KTpAehqoxGG96kmaOz4DQ6BKsGdg8BvuG9W7G9wEoU6pBSPgblnTyVvqYvoOrG_TbK3T0K-a3xyWfeEnqW3omTyN_lWhLInZYCejIqxkgVgqGguZxgB5AV0JC77pyxEKs2DRu642mlsqEDZQ" + "value": "eyJraWQiOiJaTktsNEx3c1NcL0xyYVdwaGVtcHE4OWVLWk05eUtUemtUQW40ZlM2bXFtST0iLCJhbGciOiJSUzI1NiJ9.eyJzdWIiOiI1ODY0NWVjYS1mNDllLTQ1YTktOWI0ZC1lNTg0M2RhZWNjNWUiLCJlbWFpbF92ZXJpZmllZCI6dHJ1ZSwiaXNzIjoiaHR0cHM6XC9cL2NvZ25pdG8taWRwLmV1LWNlbnRyYWwtMS5hbWF6b25hd3MuY29tXC9ldS1jZW50cmFsLTFfWE5GWDNIMzE0IiwiY29nbml0bzp1c2VybmFtZSI6IjU4NjQ1ZWNhLWY0OWUtNDVhOS05YjRkLWU1ODQzZGFlY2M1ZSIsIm9yaWdpbl9qdGkiOiJiOTZmZDY0Zi05MWEwLTRmMmMtYTk2OC1kYmRkNDcxMTY4ZDYiLCJhdWQiOiI0amNsZG9ib2YycWJuc3NtN2YxMDdnbGlxOCIsImV2ZW50X2lkIjoiZDU5ZWE4NWYtZjQ4ZC00MWE1LTlmOGItYWQ1Njk4N2FiYWJiIiwidG9rZW5fdXNlIjoiaWQiLCJhdXRoX3RpbWUiOjE3MjA3NzQyOTAsImV4cCI6MTcyMDc3Nzg5MSwiaWF0IjoxNzIwNzc0MjkxLCJjdXN0b206cGFzc19pZCI6IjczOTAzMCIsImp0aSI6ImJhYzZlZGYxLTRiNGQtNDlkOC04ZDQ4LWY1ZWVkNWM2MmZhOSIsImVtYWlsIjoianAucmFudUBjb2dpcC5kZSJ9.B9XsvDvfUatg9Mf0EEX-Z1tTi7bBzqZisa_8UaBR24O1nov_86N7XnPPVc92NtdXcHZItaSBQxAPPhWdHBwW-W8JAAoCHFo7LoouakwR8i5zfaMFG5JWhsf4Ifw6vqbxTnRUdOawBUlrr6saJgeo9uKyMd-KwBdxwMIuASNtZ0glVUecHPeHhoU_QVNTYzkAhVYiBHPF3YvyOYuRuW7gDI5mD26oMZm62XoekEq1IK-hq_P_BzmJ0b6RZZASvvo5CCkjlGUF8eweYwMfGROYaGh5e6K6wcN-C2R3MnXKROifGCTaoBEnCdt990WNNwbUY9CtinQanhZ6m11CI7ZkQg" }, { "name": "CognitoIdentityServiceProvider.4jcldobof2qbnssm7f107gliq8.58645eca-f49e-45a9-9b4d-e5843daecc5e.refreshToken", - "value": "eyJjdHkiOiJKV1QiLCJlbmMiOiJBMjU2R0NNIiwiYWxnIjoiUlNBLU9BRVAifQ.ej0FDIw3VwTFabbv_Xrthwn6QRxOrGSlTP8P-hM3xyDmhigcIepCgEUlgjSO-taBevdDgiDNuRZ2ymbsmSHjBTgtPPhBJMlNW1CJMFpf34cnHp8P8fNso7KVZH98CVT8a-klxeNUw8sJbzV76E2pefGPiKahMbgNcct6I4C0lmK60569b1ADgDJUXoZ3ZWLM5h7dmu2_zEwcu3rcJSAZvqLBQBrBhw1ck2tivoMVl0Rp3rRDmYCkbvjYpVxozv_KCBA1pKdm_n1E78T4nlJR12UVZKwGj4TnM3_AiV43J-FUKkj-rDEoPfJrWlZh0J3aV403sDGeO_R7C8zOvMz8qQ.HTEsnaMZSmoB5bMT.CPMenx7Y1fkZnG3xdudDXwto0S9nXhlrviwGAUaEV0PdAiN1JRyWyfd2gfZ9gqDJ6CxBog-kZ45nttrdY2JjS71HgBfrg3RAqRqUyiRd9OLUTtHXgysdf6tXGZYqm2j62uTzq5aYWwr_KUMEYKqH45TrxAEnBGlCaKX5ielLghK6ZA_EWrOK3oJW3aM_-mZKD0vrJd9_iwVAUMKk_hdCF1UFqsuVHXZqXxQ_iOPzyd_t5Ui_2WgVqqLZTteAsFwr_L_TqpoM11AgSH-8a1ad05JwCdeMxyhZnW8Gf172Yt7pVzUFuV491KAxXdsgxCbFIhReYhOqABCsS9fKKbi6VBDtDBrRqGeiHgfOapVMLeg8-Va-_YGa1_4oRbX_zye_HTz3WE-xmBBwt98PVEJp4pWr2lY7wDgisqzLgI8foWm1YVWFD5rypAsJxEu-9-25SVErMVlptRaZ650YFHWNrkEr3oeqzwriIxMEjm92gxgVPQOO0Q5gqj9WcUHrbeq01xr6WBhX84AqGqTpT-kxbSrFBxHFMM3zhPey4ElJ2unc_ppj2r96e3FNjTmhRdhYYz827oewmJZZwhAF2KI8a_MEz6-W18b5ju0teM4lWBWRedq8IMeTFuEZ8-nlkQTiDnsSFXqZNtFVfJGcbKKTX8LCm708DrG5QGvqjycOkXrrnw-OCaUibCWbymJzwYdPD1sLLhitMpgI6pKW8H74K7bIb_v2IeMo3hH9gm2n6SI120EpD7n74UCIGx1fn5CB28neuj-_BegrcZNd6KEs0iPEhNOpHKd7k_G8riKX-ZtKIQcqZ8MtwAvjWVVFELEkpXR2IwfW2jXzBObIvcDYYNVijroFUZ-8oObp0dAIaUFtoByIzw3VOzOc4qbCSyelFC1YyoZJgbNW2ic6ZvL8pdzYTogjI_XHakVLBk8jeRg95SXtz9XzpLyx_ZoTX5LzEh5T897tOePl1NmIptU17IiBuwxFj_nYoVgDYbbGz1ox9vEWdrAE6EpfzhFrxWVMijyfjyauWaixri-harPAbhirrGG7QEeURqv0LCMMy1w3LyaZ9p9saG3DzX0yzrERgXMNvbFi4OYY3Cb0O8bo0kjHVY7a6Yj_qKKpfIKGclRKmndxkLK5A6JJkqy4fSLK-v9RbpWUiTC-_0L2k9lEGiK5rgPhMSRhyI5XYUW1rbB_XEKPU12M5uxER0NvjomXgTUy0yOdbDfpIYb89Bs2BK-SE0MAJSepzC8bsW4CWOnfCWGnuOGQphRfCuxAIkvd-4Lwm-Nyt8-Mmvh5VhQw79v8mx2eZNzk4DyiTDbSQUwdoCoEpgyoQnvnxObYVxXUeixB.LW8iCOUVXGCbeHw2rTF6Uw" + "value": "eyJjdHkiOiJKV1QiLCJlbmMiOiJBMjU2R0NNIiwiYWxnIjoiUlNBLU9BRVAifQ.imuPu0l2BWRSCp5Deo-kkfjqrbXvrMOC7aLb73FLvWMEbZ_8wYPMIYDBVxWXCOue9lBOYWmBZ-gYmOpFjuub48kr0YH2XmS0CWvAjVaFOd1SLtA1JqPNCjzOhr4HqHNzY2p1v-LlWVkZMb6yzSJCo2i69X_uMhjI7vkwF5JBRLPfnhgpbTtuAfShe2fxwFVF3wcnIGwxwf9Mewftjw0vYAnU25kcUALthY_7os1vXG10B0HLJFlfG8AA0AZgOWin7YEYtNCR0fyILwVQLLrwrN1Df9I6nw0BT82u37GAZSihBNUekCBmLRf_eLad4DACY5YTwywzQjfLWIv6by0SYQ.32xpzYSlssbruFav.hmnVMOwHMa4fnXFrO_Eu402cEKhzl-uS_62OC51WXTOrY0qSXAGSjQLUleR8Aznkugbt738kCq7wzHeOxydaKdBIJC-hYfI3T1sFFBWPkyEjAmLPy6FI2FeFdKzFrIEOsKYyEQ_7R8uOzarTXnBr0wHBKyKqRhAmZpUO9ytMS2HHNd39Ta8kwDtkA848k-3XQ1J3we0r5w177Kp8jgZv2lmItu17Z3Q8xZbZNuZwdG2pyDUTJpoQRdbrhBFfPi2x5Arm3tSbOCX3eF_TOnFA5EPfuJF_OQkzFN1FgnJcXwY63VKcy4EzR02njK6WLDzECekK7ly_hAk83Rcon7NSWj0R-QCmtJu92MIwQ1VwOpfKZSG9s8w9V4TcFaRM7y_1CS8sa6hMiM6j1mvWsEk1pu-MyqsV-nZi6HRqtbCXAgrzkQ0JyrqHM17pLwoMC-YzHFVkYO2x9JvszbNg85QVC50e7HKEpg8DEfoXz-i686zxOCjEBTIzHEEs4L7ZgHm9wjKUdC7iyGdMxr1DhO4VFWxUENYJrDgFoUyHFmZbiz6tUzxYwZfYhJP-jb1UKNNYXl477kgmcr5x4nM0ShSWnKLiPUOkeez2D9THXLdPFliXiGfbL126AJMsSS16oiW9DaSfq6mikjiuBZhhLEKboRbzBVAAFx55BjWKs_x7O9MMbHGFeX5AQAfkgTbFKy92sahH_MimP7JQn7yx-AQefJpiKHt4aVoLTs2c09ytEgBQkY7m-zaRKAwCIUIa3IG4N2SU8aU0rDgg9_QXG6WV2G7M6GxEMqjeBU_o3CqS-2XP5lyxF5abY4yoxtiMbngXG-YrPcxQqMWX0SaRZSIp5vwKfc8CoELs0kmpZpJ3pJLwSCdmfrKqp4_fAGvYWB0UpAsUN9IqvYDROkCZlJMCh5X0N5U01jxjSOQFYDpQrkNQ4lwt1VQeAphH5ohPD0XRq3xm7amsouF6D2B0cmZIRSKf6yR013jL85RmKMxXQTHyFHLo5QCoUjgTfl6QfO11W7RUcitXtuG3Dthyx3NQ9Y9kypdZ3qJBg-RjQdIhJPVOUvjTDzka81tnLK3TisSjKEg8NSPeA0F-gihIPz5R88rKAWT_BKa4ugEjGuEKMdccglXmcFxkGMq-AR87t5Wfa9Ft2F5OS9rZuunpLXsHGRcQRvx46zfW_AvV0FOAgHDJvJ3FdWiIfN9Zazi5NnM5E-ZCtg9mlWYpxTn3_gljob8pOgD_AVltpsRMvgSmV5g_NwJTAqp8vQGQMNEg-ZFb3UtG4hpbHFre0CxQQ3iXfMF8bla5APL90ABvAtZHQMcsTaiOAMkCnzUmTVIgqcM4D2vH.wyRM3-165fGB8NIdapX8iA" } ] } diff --git a/agent/.session/token.json b/agent/.session/token.json new file mode 100644 index 0000000..7ef1bcb --- /dev/null +++ b/agent/.session/token.json @@ -0,0 +1 @@ +{"token":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiI2Njc5YTA2ZmRjY2NiYmUwMGMzYTc4NjgiLCJlbWFpbCI6ImFnZW50QGFnZW50LmNvbSIsImlhdCI6MTcyMjk1NTI3NywiZXhwIjoxNzI1NTQ3Mjc3LCJhdWQiOiJ5b3Vyc2l0ZSIsImlzcyI6Imp1Y3VuZHVzLmNvbSJ9.K9uGLVH42tfajV7mt_G66-iZVmgUFNLBmPNKinZ4B4o"} \ No newline at end of file diff --git a/agent/Dockerfile.dev b/agent/Dockerfile.dev index 5b10a09..ac96040 100644 --- a/agent/Dockerfile.dev +++ b/agent/Dockerfile.dev @@ -15,6 +15,9 @@ RUN apt-get update && apt-get install gnupg wget -y && \ # Install Playwright RUN npx -y playwright@1.44.0 install --with-deps +# install ffmpeg +RUN apt-get update && apt-get install ffmpeg -y + # Setting up the work directory WORKDIR /agent diff --git a/agent/config.js b/agent/config.js new file mode 100755 index 0000000..e69de29 diff --git a/agent/index.js b/agent/index.js index 8e5a3d6..b1732b6 100644 --- a/agent/index.js +++ b/agent/index.js @@ -4,9 +4,6 @@ const app = express() var bodyParser = require('body-parser'); app.use(bodyParser.json()) -//const puppeteer = require('puppeteer'); -//const puppeteerPackage = require('puppeteer/package.json'); - const puppeteer = require('puppeteer-extra'); const pluginStealth = require('puppeteer-extra-plugin-stealth'); puppeteer.use(pluginStealth()) diff --git a/agent/middleware/validateToken.js b/agent/middleware/validateToken.js new file mode 100644 index 0000000..abe2c19 --- /dev/null +++ b/agent/middleware/validateToken.js @@ -0,0 +1,25 @@ +const { Key } = require("../.Key.js"); + +const validateInternToken = () => { + return (req, res, next) => { + const token = req.headers['authorization']; + console.log(`Token provided: ${token}`); + + if (!token) { + console.log("No token provided"); + return res.status(403).send({ message: 'No token provided.' }); + } + + console.log(`Expected token: ${Key.internToken}`); + + if (token === Key.internToken) { + console.log("Token valid, calling next()"); + next(); + } else { + console.log("Unauthorized access attempt"); + return res.status(401).send({ message: 'Unauthorized.' }); + } + } +} + +module.exports = { validateInternToken }; \ No newline at end of file diff --git a/agent/package-lock.json b/agent/package-lock.json index 318666c..e3768bc 100644 --- a/agent/package-lock.json +++ b/agent/package-lock.json @@ -15,6 +15,7 @@ "express-async-handler": "^1.2.0", "moment-timezone": "^0.5.45", "node-fetch": "^2.6.1", + "node-webrtc": "^0.0.0", "protobufjs": "^7.3.0", "puppeteer": "^22.10.0", "puppeteer-extra": "^3.3.6", @@ -1776,6 +1777,17 @@ } } }, + "node_modules/node-webrtc": { + "version": "0.0.0", + "resolved": "https://registry.npmjs.org/node-webrtc/-/node-webrtc-0.0.0.tgz", + "integrity": "sha512-8EXsvPcAhveVs8IOyglv0F6tdzYVgJ5ujoXVk+XRw/UoCifCsoi2oARkG0HcYUL2j0U8kNPMsVU3SFaFxMZMeA==", + "bin": { + "node-webrtc": "bin/node-webrtc" + }, + "engines": { + "node": ">= 0.5.0 < 0.7.0" + } + }, "node_modules/nodemon": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-3.1.0.tgz", diff --git a/agent/package.json b/agent/package.json index 7d44fb2..36c50d1 100644 --- a/agent/package.json +++ b/agent/package.json @@ -17,6 +17,7 @@ "express-async-handler": "^1.2.0", "moment-timezone": "^0.5.45", "node-fetch": "^2.6.1", + "node-webrtc": "^0.0.0", "protobufjs": "^7.3.0", "puppeteer": "^22.10.0", "puppeteer-extra": "^3.3.6", diff --git a/agent/routes/follow.js b/agent/routes/follow.js index 50436cb..56b3aa5 100644 --- a/agent/routes/follow.js +++ b/agent/routes/follow.js @@ -1,6 +1,7 @@ const controllers = require('../controllers/follow') const router = require('express').Router() +const { validateInternToken } = require('../middleware/validateToken'); -router.get('/sale/:url', controllers.sale) +router.get('/sale/:url',validateInternToken(), controllers.sale) module.exports = router \ No newline at end of file diff --git a/config.js b/config.js new file mode 100644 index 0000000..c16cec0 --- /dev/null +++ b/config.js @@ -0,0 +1,12 @@ +const config = { + jucundus: { + url: 'http://host.docker.internal:3000', + useremail: 'agent@agent.com' + }, + agent: { + urlApi: 'http://agent/internApi', + maxCloseWebsockets: 5, + } +}; + +module.exports = { config }; \ No newline at end of file diff --git a/docker-compose-dev.yml b/docker-compose-dev.yml index 534a530..45900aa 100644 --- a/docker-compose-dev.yml +++ b/docker-compose-dev.yml @@ -7,6 +7,8 @@ services: dockerfile: Dockerfile.dev volumes: - ./agent:/agent + - ./.Key.js:/agent/.Key.js + - ./config.js:/agent/config.js - ./AuctionServices:/agent/AuctionServices networks: - internal @@ -21,6 +23,8 @@ services: - 3020:3020 volumes: - ./scrapper:/scrapper + - ./.Key.js:/scrapper/.Key.js + - ./config.js:/scrapper/config.js - ./AuctionServices:/scrapper/AuctionServices networks: - internal diff --git a/scrapper/config.js b/scrapper/config.js new file mode 100755 index 0000000..e69de29 diff --git a/scrapper/controllers/sale.js b/scrapper/controllers/sale.js index d81eb2a..f2a3feb 100644 --- a/scrapper/controllers/sale.js +++ b/scrapper/controllers/sale.js @@ -5,6 +5,9 @@ const {ScraperTools} = require('../AuctionServices/Scraper/Scraper.js') const Drouot = require('../AuctionServices/Scraper/Drouot/Drouot.js') const Interencheres = require('../AuctionServices/Scraper/Interencheres/Interencheres.js') +const {config} = require('../config.js'); + +const { Key } = require("../.Key.js"); let getAuctionPlatform = function(Url){ @@ -88,7 +91,7 @@ exports.getLotList = asyncHandler(async (req, res, next) => { } }); -// ## AGENT PUPPETEER +// ## AGENT PUPPETEER/PLAYWRIGHT //Follow a live Sale exports.followSale = asyncHandler(async (req, res, next) => { @@ -103,12 +106,16 @@ exports.followSale = asyncHandler(async (req, res, next) => { try{ let AuctionPlatform = getAuctionPlatform(url); if(AuctionPlatform){ - console.log('Scrapper followSale : '+encodeURIComponent(url)) - fetch('http://agent/internApi/follow/sale/'+encodeURIComponent(url)) + + fetch(config.agent.urlApi+'/follow/sale/'+encodeURIComponent(url),{ + headers: { + 'authorization': Key.internToken + } + }) .then(response => { - console.log("fetch OK") - //response.json() - } ) + console.log("fetch OK") + //response.json() + } ) .then(saleInfo => {}) .catch(error => { console.error(error); diff --git a/scrapper/middleware/validateToken.js b/scrapper/middleware/validateToken.js new file mode 100644 index 0000000..af35404 --- /dev/null +++ b/scrapper/middleware/validateToken.js @@ -0,0 +1,24 @@ +const { Key } = require("../.Key.js"); + +const validateToken = () => { + return (req, res, next) => { + const token = req.headers['authorization']; + + if (!token) { + console.log("No token provided"); + return res.status(403).send({ message: 'No token provided.' }); + } + + console.log(`Expected token: ${Key.token}`); + + if (token === Key.token) { + console.log("Token valid, calling next()"); + next(); + } else { + console.log("Unauthorized access attempt"); + return res.status(401).send({ message: 'Unauthorized.' }); + } + } +} + +module.exports = { validateToken }; \ No newline at end of file diff --git a/scrapper/routes/lot.js b/scrapper/routes/lot.js index c4a5a15..3f11af6 100644 --- a/scrapper/routes/lot.js +++ b/scrapper/routes/lot.js @@ -1,7 +1,8 @@ const controllers = require('../controllers/lot') const router = require('express').Router() +const { validateToken } = require('../middleware/validateToken'); -router.get('/getPictures/:url', controllers.getPictures) -router.get('/getInfos/:url', controllers.getInfos) +router.get('/getPictures/:url', validateToken(),controllers.getPictures) +router.get('/getInfos/:url', validateToken(),controllers.getInfos) module.exports = router \ No newline at end of file diff --git a/scrapper/routes/sale.js b/scrapper/routes/sale.js index 869e17d..f25b1db 100644 --- a/scrapper/routes/sale.js +++ b/scrapper/routes/sale.js @@ -1,8 +1,9 @@ const controllers = require('../controllers/sale') const router = require('express').Router() +const { validateToken } = require('../middleware/validateToken'); -router.get('/getSaleInfos/:url', controllers.getSaleInfos) -router.get('/getLotList/:url', controllers.getLotList) -router.get('/followSale/:url', controllers.followSale) +router.get('/getSaleInfos/:url', validateToken(), controllers.getSaleInfos) +router.get('/getLotList/:url', validateToken(), controllers.getLotList) +router.get('/followSale/:url', validateToken(), controllers.followSale) module.exports = router \ No newline at end of file