{"version":3,"sources":["components/Preamble/index.js","components/ClientId/index.js","components/ClientSecret/index.js","components/Tokens/index.js","components/Tenants/index.js","components/Scope/index.js","components/App/utils.js","components/App/index.js","serviceWorker.js","index.js"],"names":["Preamble","target","rel","href","window","location","origin","ClientId","clientId","setClientId","handleConnect","onSubmit","event","preventDefault","style","width","name","type","value","onChange","required","margin","ClientSecret","clientSecret","setClientSecret","getTokens","Tokens","token","access_token","onClick","navigator","clipboard","writeText","refresh_token","Tenants","tenantRows","tenants","map","tenant","index","tenantId","tenantType","otherScopes","accountingScopes","payrollScopes","CheckboxList","scopes","handleChange","display","verticalAlign","listStyle","item","key","checked","Scope","setScopes","e","concat","filter","createCheckedScopes","scopeArray","some","checkedItem","GetToken","code","a","async","config","method","body","JSON","stringify","headers","fetch","process","response","json","GetTenants","accessToken","App","useState","sessionStorage","getItem","parse","setCode","setToken","isGettingToken","setIsGettingToken","setTenants","isGettingTenants","setIsGettingTenants","React","useEffect","setItem","utils","updateTokens","useCallback","alert","updateTenants","pathname","URLSearchParams","search","get","history","pushState","scope","query","toString","join","Boolean","hostname","match","ReactDOM","render","document","getElementById","serviceWorker","ready","then","registration","unregister"],"mappings":"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","file":"static/js/main.42436d0d.chunk.js","sourcesContent":["import React from 'react';\r\n\r\nfunction Preamble(){\r\n return(\r\n
\r\n

Xero OAuth2 Access Tokens.

\r\n

Use this tool to get Xero access tokens for your Xero Apps that do not have user interfaces e.g.\r\n integrations using the Xero API running on servers in the background.\r\n

\r\n

How it works

\r\n

Prerequisites:

\r\n \r\n

Step 1: Select the scopes your Xero App requires.

\r\n

Step 2: Provide the client id of your Xero App and connect to Xero. Xero will ask you to login and approve the connection and scopes.

\r\n

Step 3: Provide the client secret of your Xero App and get the access tokens from Xero. \r\n The request can only be done server side so we call an API hosted on a Linx Server to forward \r\n the request and return the tokens. No client data or tokens are saved or logged on the Linx Server.

\r\n

Step 4: The tenants connected to your Xero App are requested and displayed. A tenant id is required to make calls to Xero APIs. \r\n This request is also done through the API hosted on Linx.\r\n

\r\n

Source code

\r\n \r\n

Warning

\r\n

Your Xero App credentials and Xero organisation access tokens are visible in your browser and flows through an API not \r\n under your control. Only use this for testing purposes using a demo company. For production use your \r\n own Linx Server to request the tokens.

\r\n
\r\n );\r\n};\r\n\r\nexport default Preamble","import React from 'react';\r\n\r\nfunction ClientId({clientId, setClientId, handleConnect}){\r\n\r\n const onSubmit = event => {\r\n handleConnect();\r\n event.preventDefault();\r\n }\r\n\r\n return (\r\n
\r\n

Step 2: Provide your client id and connect to Xero

\r\n \r\n setClientId(event.target.value)} required />\r\n \r\n
\r\n )\r\n}\r\n\r\nexport default ClientId;","import React from 'react';\r\n\r\nfunction ClientSecret({clientSecret, setClientSecret, getTokens}){\r\n\r\n const onSubmit = event => {\r\n getTokens();\r\n event.preventDefault();\r\n }\r\n\r\n return (\r\n
\r\n

Step 3: Provide your client secret and get access tokens

\r\n \r\n setClientSecret(event.target.value)} required />\r\n \r\n
\r\n )\r\n}\r\n\r\nexport default ClientSecret;","import React from 'react';\r\n\r\nfunction Tokens({token}){\r\n return(\r\n
\r\n

Tokens

\r\n

Access token

\r\n

{token.access_token} \r\n

\r\n\r\n

Refresh token

\r\n

{token.refresh_token} \r\n

\r\n
\r\n )\r\n}\r\n\r\nexport default Tokens;","import React from 'react';\r\n\r\nfunction Tenants({tenants}){\r\n const tenantRows = tenants.map((tenant, index) => {\r\n return(\r\n \r\n {tenant.tenantId} \r\n \r\n {tenant.tenantType}\r\n \r\n )\r\n });\r\n\r\n return(\r\n
\r\n

Tenants

\r\n \r\n \r\n \r\n \r\n {tenantRows}\r\n
Tenant idTenant type
\r\n
\r\n )\r\n}\r\n\r\nexport default Tenants;","import React from 'react';\r\n\r\nconst otherScopes = [\r\n \"files\",\r\n \"files.read\",\r\n \"assets\",\r\n \"assets.read\",\r\n \"projects\",\r\n \"projects.read\"\r\n]\r\n\r\nconst accountingScopes = [\r\n \"accounting.transactions\",\r\n \"accounting.transactions.read\",\r\n \"accounting.reports.read\",\r\n \"accounting.journals.read\",\r\n \"accounting.settings\",\r\n \"accounting.settings.read\",\r\n \"accounting.contacts\",\r\n \"accounting.contacts.read\",\r\n \"accounting.attachments\",\r\n \"accounting.attachments.read\"\r\n]\r\n\r\nconst payrollScopes = [\r\n \"payroll.employees\",\r\n \"payroll.employees.read\",\r\n \"payroll.payruns\",\r\n \"payroll.payruns.read\",\r\n \"payroll.payslip\",\r\n \"payroll.payslip.read\",\r\n \"payroll.timesheets\",\r\n \"payroll.timesheets.read\",\r\n \"payroll.settings\",\r\n \"payroll.settings.read\"\r\n]\r\n\r\nconst CheckboxList = ({scopes, handleChange})=>\r\n
\r\n \r\n
;\r\n\r\nfunction Scope({scopes, setScopes}){\r\n const handleChange = (e)=>{\r\n if(e.target.checked){\r\n setScopes(scopes.concat(e.target.name));\r\n }\r\n else{\r\n setScopes(scopes.filter((value)=>value!==e.target.name));\r\n }\r\n }\r\n\r\n const createCheckedScopes = (scopeArray)=>{\r\n return scopeArray.map(item=>{\r\n return {\"name\": item, \"checked\": scopes.some(checkedItem=>item===checkedItem)};\r\n });\r\n }\r\n\r\n return (\r\n
\r\n

Step 1: Select the scopes required by your Xero App

\r\n

'offline_access' scope is automatically included. For more about scopes \r\n see the Xero scopes documentation

\r\n \r\n \r\n \r\n
\r\n )\r\n}\r\n\r\nexport default Scope;","export async function GetToken(clientId, clientSecret, code){\r\n let config = {\r\n method: \"POST\",\r\n body: JSON.stringify({\r\n \"clientId\": clientId,\r\n \"clientSecret\": clientSecret,\r\n \"code\": code,\r\n \"redirectUri\": window.location.origin + \"/auth\"\r\n }),\r\n headers: {\r\n \"Content-Type\": \"application/json\"\r\n }\r\n };\r\n \r\n let response = await fetch(process.env.REACT_APP_API_HOST + \"/token\", config);\r\n return response.json();\r\n }\r\n\r\n export function ConnectToXero(clientId, scope){\r\n const query = new URLSearchParams({\r\n \"response_type\": \"code\",\r\n \"client_id\": clientId,\r\n \"redirect_uri\": window.location.origin + \"/auth\",\r\n \"scope\": \"offline_access \" + scope,\r\n \"state\": \"test\"\r\n });\r\n window.location = `https://login.xero.com/identity/connect/authorize?${query.toString()}`;\r\n }\r\n \r\n export async function GetTenants(accessToken){\r\n let response = await fetch(process.env.REACT_APP_API_HOST + `/tenants?accessToken=${accessToken}`);\r\n return response.json();\r\n }\r\n \r\n export function StoreClientId(clientId){\r\n sessionStorage.setItem(\"clientId\", clientId);\r\n }\r\n \r\n export function GetClientIdFromStore(){\r\n return sessionStorage.getItem(\"clientId\")||\"\";\r\n }\r\n \r\n export function StoreScopes(scopes){\r\n sessionStorage.setItem(\"scopes\", JSON.stringify(scopes));\r\n }\r\n \r\n export function GetScopesFromStore(){\r\n return JSON.parse(sessionStorage.getItem(\"scopes\")||\"[]\");\r\n }","import React, {useState, useCallback} from 'react';\r\nimport Preamble from '../Preamble';\r\nimport ClientId from '../ClientId';\r\nimport ClientSecret from '../ClientSecret';\r\nimport Tokens from '../Tokens';\r\nimport Tenants from '../Tenants';\r\nimport Scope from '../Scope';\r\nimport * as utils from './utils';\r\n\r\nfunction App() {\r\n const [clientId, setClientId] = useState(utils.GetClientIdFromStore());\r\n const [scopes, setScopes] = useState(utils.GetScopesFromStore());\r\n const [code, setCode] = useState(\"\");\r\n const [clientSecret, setClientSecret] = useState(\"\");\r\n const [token, setToken] = useState(\"\");\r\n const [isGettingToken, setIsGettingToken] = useState(false);\r\n const [tenants, setTenants] = useState(\"\");\r\n const [isGettingTenants, setIsGettingTenants] = useState(false);\r\n\r\n React.useEffect(()=>{\r\n utils.StoreScopes(scopes);\r\n utils.StoreClientId(clientId);\r\n }, [scopes, clientId]);\r\n\r\n const updateTokens = useCallback(async () => {\r\n try{\r\n const token = await utils.GetToken(clientId, clientSecret, code);\r\n setToken(token);\r\n setIsGettingTenants(true);\r\n }\r\n catch{\r\n alert(`Something went wrong. Possible causes are\r\n - Client secret is incorrect.\r\n - 5min have passed since connecting to Xero. Please Connect to Xero again.\r\n - Your network is down.`);\r\n }\r\n setIsGettingToken(false);\r\n }, [clientId, clientSecret, code]);\r\n\r\n React.useEffect(()=>{\r\n if(isGettingToken){\r\n updateTokens();\r\n }\r\n }, [isGettingToken, updateTokens]);\r\n\r\n const updateTenants = useCallback(async () => {\r\n try{\r\n const tenants = await utils.GetTenants(token.access_token);\r\n setTenants(tenants);\r\n }\r\n catch{\r\n alert(`Something went wrong getting your tenants. You can get your tenants using Postman or Linx.`);\r\n }\r\n setIsGettingTenants(false);\r\n }, [token]);\r\n\r\n React.useEffect(()=>{\r\n if(isGettingTenants){\r\n updateTenants();\r\n }\r\n }, [isGettingTenants, updateTenants]);\r\n\r\n if(window.location.pathname===\"/auth\" && code === \"\")\r\n {\r\n const query = new URLSearchParams(window.location.search);\r\n setCode(query.get(\"code\"));\r\n window.history.pushState(\"\",\"\",\"/\");\r\n }\r\n\r\n return (\r\n
\r\n \r\n \r\n utils.ConnectToXero(clientId, scopes.join(\" \"))}/>\r\n {code !== \"\" && setIsGettingToken(true)}>\r\n }\r\n {isGettingToken === true &&

getting the tokens...

}\r\n {token !== \"\" && }\r\n {isGettingTenants === true &&

getting the tenants...

}\r\n {tenants !== \"\" && }\r\n
\r\n );\r\n}\r\n\r\nexport default App;\r\n","// This optional code is used to register a service worker.\r\n// register() is not called by default.\r\n\r\n// This lets the app load faster on subsequent visits in production, and gives\r\n// it offline capabilities. However, it also means that developers (and users)\r\n// will only see deployed updates on subsequent visits to a page, after all the\r\n// existing tabs open on the page have been closed, since previously cached\r\n// resources are updated in the background.\r\n\r\n// To learn more about the benefits of this model and instructions on how to\r\n// opt-in, read https://bit.ly/CRA-PWA\r\n\r\nconst isLocalhost = Boolean(\r\n window.location.hostname === 'localhost' ||\r\n // [::1] is the IPv6 localhost address.\r\n window.location.hostname === '[::1]' ||\r\n // 127.0.0.0/8 are considered localhost for IPv4.\r\n window.location.hostname.match(\r\n /^127(?:\\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$/\r\n )\r\n);\r\n\r\nexport function register(config) {\r\n if (process.env.NODE_ENV === 'production' && 'serviceWorker' in navigator) {\r\n // The URL constructor is available in all browsers that support SW.\r\n const publicUrl = new URL(process.env.PUBLIC_URL, window.location.href);\r\n if (publicUrl.origin !== window.location.origin) {\r\n // Our service worker won't work if PUBLIC_URL is on a different origin\r\n // from what our page is served on. This might happen if a CDN is used to\r\n // serve assets; see https://github.com/facebook/create-react-app/issues/2374\r\n return;\r\n }\r\n\r\n window.addEventListener('load', () => {\r\n const swUrl = `${process.env.PUBLIC_URL}/service-worker.js`;\r\n\r\n if (isLocalhost) {\r\n // This is running on localhost. Let's check if a service worker still exists or not.\r\n checkValidServiceWorker(swUrl, config);\r\n\r\n // Add some additional logging to localhost, pointing developers to the\r\n // service worker/PWA documentation.\r\n navigator.serviceWorker.ready.then(() => {\r\n console.log(\r\n 'This web app is being served cache-first by a service ' +\r\n 'worker. To learn more, visit https://bit.ly/CRA-PWA'\r\n );\r\n });\r\n } else {\r\n // Is not localhost. Just register service worker\r\n registerValidSW(swUrl, config);\r\n }\r\n });\r\n }\r\n}\r\n\r\nfunction registerValidSW(swUrl, config) {\r\n navigator.serviceWorker\r\n .register(swUrl)\r\n .then(registration => {\r\n registration.onupdatefound = () => {\r\n const installingWorker = registration.installing;\r\n if (installingWorker == null) {\r\n return;\r\n }\r\n installingWorker.onstatechange = () => {\r\n if (installingWorker.state === 'installed') {\r\n if (navigator.serviceWorker.controller) {\r\n // At this point, the updated precached content has been fetched,\r\n // but the previous service worker will still serve the older\r\n // content until all client tabs are closed.\r\n console.log(\r\n 'New content is available and will be used when all ' +\r\n 'tabs for this page are closed. See https://bit.ly/CRA-PWA.'\r\n );\r\n\r\n // Execute callback\r\n if (config && config.onUpdate) {\r\n config.onUpdate(registration);\r\n }\r\n } else {\r\n // At this point, everything has been precached.\r\n // It's the perfect time to display a\r\n // \"Content is cached for offline use.\" message.\r\n console.log('Content is cached for offline use.');\r\n\r\n // Execute callback\r\n if (config && config.onSuccess) {\r\n config.onSuccess(registration);\r\n }\r\n }\r\n }\r\n };\r\n };\r\n })\r\n .catch(error => {\r\n console.error('Error during service worker registration:', error);\r\n });\r\n}\r\n\r\nfunction checkValidServiceWorker(swUrl, config) {\r\n // Check if the service worker can be found. If it can't reload the page.\r\n fetch(swUrl, {\r\n headers: { 'Service-Worker': 'script' }\r\n })\r\n .then(response => {\r\n // Ensure service worker exists, and that we really are getting a JS file.\r\n const contentType = response.headers.get('content-type');\r\n if (\r\n response.status === 404 ||\r\n (contentType != null && contentType.indexOf('javascript') === -1)\r\n ) {\r\n // No service worker found. Probably a different app. Reload the page.\r\n navigator.serviceWorker.ready.then(registration => {\r\n registration.unregister().then(() => {\r\n window.location.reload();\r\n });\r\n });\r\n } else {\r\n // Service worker found. Proceed as normal.\r\n registerValidSW(swUrl, config);\r\n }\r\n })\r\n .catch(() => {\r\n console.log(\r\n 'No internet connection found. App is running in offline mode.'\r\n );\r\n });\r\n}\r\n\r\nexport function unregister() {\r\n if ('serviceWorker' in navigator) {\r\n navigator.serviceWorker.ready.then(registration => {\r\n registration.unregister();\r\n });\r\n }\r\n}\r\n","import React from 'react';\r\nimport ReactDOM from 'react-dom';\r\nimport './index.css';\r\nimport App from './components/App';\r\nimport * as serviceWorker from './serviceWorker';\r\n\r\nReactDOM.render(, document.getElementById('root'));\r\n\r\n// If you want your app to work offline and load faster, you can change\r\n// unregister() to register() below. Note this comes with some pitfalls.\r\n// Learn more about service workers: https://bit.ly/CRA-PWA\r\nserviceWorker.unregister();\r\n"],"sourceRoot":""}