Skip to content

Commit

Permalink
Merge pull request #444 from dot-mike/feat/extensions-fpfss
Browse files Browse the repository at this point in the history
Extend fpfss access token into extensions
  • Loading branch information
colin969 authored Dec 10, 2024
2 parents c423f91 + e940d75 commit d0cecac
Show file tree
Hide file tree
Showing 11 changed files with 226 additions and 51 deletions.
10 changes: 8 additions & 2 deletions lang/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -545,7 +545,8 @@
"showImage": "Show Image",
"searching": "Searching...",
"loading": "Loading...",
"ok": "OK"
"ok": "OK",
"allow": "Allow"
},
"menu": {
"viewThumbnailInFolder": "View Thumbnail in Folder",
Expand Down Expand Up @@ -639,7 +640,8 @@
"badAntiVirus": "You appear to be using '{0}'.\nThis particular Antivirus is known to cause issues, and we recommend adding an exception to the Flashpoint folder.\n\nIf you only see a white screen when running Flash games you may need to reinstall Flashpoint to restore deleted files.\n\nSee the Wiki or Help tab for detailed instructions.",
"openWiki": "Open Wiki",
"openDiscord": "Join Discord Server",
"doNotShowAgain": "Do not show again"
"doNotShowAgain": "Do not show again",
"extFpfssConsent": "Extension with ID {0} is requesting access to your FPFSS token. Allow?\nThis means the extension will be able access your FPFSS account and perform actions on your behalf."
},
"libraries": {
"arcade": "Games",
Expand All @@ -659,5 +661,9 @@
"techDesc": "Adds support for all other tech - Shockwave, Unity, Java, HTML5, etc.",
"screenshots": "Logos & Screenshots",
"screenshotsDesc": "Adds logos for Grid view and screenshots for all games."
},
"extensions": {
"fpssConsentRevokeTitle": "Revoke access to FPFSS",
"fpssConsentRevokeDesc": "Withdraw this extension's access to FPFSS"
}
}
30 changes: 28 additions & 2 deletions src/back/extensions/ApiImplementation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ import {
} from '@back/util/misc';
import { BrowsePageLayout, ScreenshotPreviewMode } from '@shared/BrowsePageLayout';
import { ILogEntry, LogLevel } from '@shared/Log/interface';
import { BackOut } from '@shared/back/types';
import { BackOut, FpfssUser } from '@shared/back/types';
import { CURATIONS_FOLDER_WORKING } from '@shared/constants';
import { CurationMeta } from '@shared/curate/types';
import { getContentFolderByKey } from '@shared/curate/util';
Expand Down Expand Up @@ -613,7 +613,32 @@ export function createApiFactory(extId: string, extManifest: IExtensionManifest,
},
extractGameFileByUrl: (url: string) => {
return '' as any; // UNIMPLEMENTED
}
},
};

const extFpfss: typeof flashpoint.fpfss = {
getAccessToken: async (): Promise<string> => {
if (!state.socketServer.lastClient) {
throw new Error('No connected client to handle FPFSS action.');
}
try {
const user = await state.socketServer.request(state.socketServer.lastClient, BackOut.FPFSS_ACTION, extId);
if (user && user.accessToken) {
return user.accessToken;
} else {
throw new Error('Failed to get access token or user cancelled.');
}
} catch (error) {
const client = state.socketServer.lastClient;
const openDialog = state.socketServer.showMessageBoxBack(state, client);
await openDialog({
largeMessage: true,
message: (error instanceof Error) ? error.message : String(error),
buttons: [state.languageContainer.misc.ok]
});
throw error;
}
},
};

// Create API Module to give to caller
Expand Down Expand Up @@ -645,6 +670,7 @@ export function createApiFactory(extId: string, extManifest: IExtensionManifest,
services: extServices,
dialogs: extDialogs,
middleware: extMiddlewares,
fpfss: extFpfss,

// Events
onDidInit: apiEmitters.onDidInit.extEvent(extManifest.displayName || extManifest.name),
Expand Down
2 changes: 1 addition & 1 deletion src/back/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import {
stringifyArray
} from '@shared/Util';
import * as os from 'os';
import { BackIn, BackInit, BackInitArgs, BackOut, BackResParams, ComponentState, ComponentStatus, DownloadDetails } from '@shared/back/types';
import { BackIn, BackInit, BackInitArgs, BackOut, BackResParams, ComponentState, ComponentStatus, DownloadDetails, FpfssUser } from '@shared/back/types';
import { getContentFolderByKey, getCurationFolder } from '@shared/curate/util';
import { ILogoSet, LogoSet } from '@shared/extensions/interfaces';
import { IBackProcessInfo, RecursivePartial } from '@shared/interfaces';
Expand Down
1 change: 1 addition & 0 deletions src/back/responses.ts
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,7 @@ import {
import { uuid } from './util/uuid';
import { FPFSS_INFO_FILENAME } from '@shared/curate/fpfss';
import { createSearchFilter } from '@back/util/search';
import { FpfssUser } from '@shared/back/types';

const axios = axiosImport.default;

Expand Down
2 changes: 1 addition & 1 deletion src/back/types.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { BackInit, ComponentStatus } from '@shared/back/types';
import { BackInit, ComponentStatus, FpfssUser } from '@shared/back/types';
import { AppConfigData, AppExtConfigData } from '@shared/config/interfaces';
import { ExecMapping, GamePropSuggestions, IBackProcessInfo, INamedBackProcessInfo } from '@shared/interfaces';
import { LangContainer, LangFile } from '@shared/lang';
Expand Down
90 changes: 63 additions & 27 deletions src/renderer/components/app.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,22 @@
import * as remote from '@electron/remote';
import { WithCurateProps } from '@renderer/containers/withCurateState';
import { WithFpfssProps } from '@renderer/containers/withFpfss';
import { WithSearchProps } from '@renderer/containers/withSearch';
import { WithViewProps } from '@renderer/containers/withView';
import { cancelDialog, RANDOM_GAME_ROW_COUNT, resolveDialog, updateDialogField } from '@renderer/store/main/slice';
import { BackIn, BackInit, BackOut, FpfssUser } from '@shared/back/types';
import { APP_TITLE, LOGOS, SCREENSHOTS, VIEW_PAGE_SIZE } from '@shared/constants';
import { APP_TITLE, LOGOS, SCREENSHOTS } from '@shared/constants';
import { CustomIPC, IService, ProcessState, WindowIPC } from '@shared/interfaces';
import { LangContainer } from '@shared/lang';
import { memoizeOne } from '@shared/memoize';
import { Paths } from '@shared/Paths';
import { updatePreferencesData } from '@shared/preferences/util';
import { setTheme } from '@shared/Theme';
import { getFileServerURL, mapFpfssGameToLocal, mapLocalToFpfssGame, recursiveReplace, sizeToString } from '@shared/Util';
import { arrayShallowStrictEquals } from '@shared/utils/compare';
import { debounce } from '@shared/utils/debounce';
import { newGame } from '@shared/utils/misc';
import { formatString } from '@shared/utils/StringFormatter';
import axios from 'axios';
import { clipboard, ipcRenderer, Menu, MenuItemConstructorOptions } from 'electron';
import {
Expand All @@ -17,47 +25,39 @@ import {
DialogState,
Game,
Playlist,
PlaylistGame, ViewGame
PlaylistGame
} from 'flashpoint-launcher';
import * as fs from 'fs-extra';
import * as path from 'path';
import * as React from 'react';
import { IWithShortcut } from 'react-keybind';
import { RouteComponentProps } from 'react-router-dom';
import { FloatingContainer } from './FloatingContainer';
import { ConnectedFpfssEditGame } from './FpfssEditGame';
import { InputField } from './InputField';
import { OpenIcon } from './OpenIcon';
import { newCurateTask } from './pages/CuratePage';
import { placeholderProgressData, ProgressBar } from './ProgressComponents';
import { ResizableSidebar, SidebarResizeEvent } from './ResizableSidebar';
import { SimpleButton } from './SimpleButton';
import { SplashScreen } from './SplashScreen';
import { TaskBar } from './TaskBar';
import { TitleBar } from './TitleBar';
import { ConnectedFooter } from '../containers/ConnectedFooter';
import { ConnectedRightBrowseSidebar } from '../containers/ConnectedRightBrowseSidebar';
import Header from '../containers/HeaderContainer';
import { WithMainStateProps } from '../containers/withMainState';
import { WithPreferencesProps } from '../containers/withPreferences';
import { WithTagCategoriesProps } from '../containers/withTagCategories';
import { WithTasksProps } from '../containers/withTasks';
import { ProgressData } from '../context/ProgressContext';
import { CreditsFile } from '../credits/CreditsFile';
import { fpfssLogin } from '../fpfss';
import { Paths } from '@shared/Paths';
import { fpfssLogin, getFpfssConsentExt, saveFpfssConsentExt } from '../fpfss';
import { AppRouter, AppRouterProps } from '../router';
import { getViewName, getGameImagePath, getGameImageURL, getGamePath, joinLibraryRoute } from '../Util';
import { getGameImagePath, getGameImageURL, getGamePath, getViewName, joinLibraryRoute } from '../Util';
import { LangContext } from '../util/lang';
import { queueOne } from '../util/queue';
import { FloatingContainer } from './FloatingContainer';
import { ConnectedFpfssEditGame } from './FpfssEditGame';
import { InputField } from './InputField';
import { OpenIcon } from './OpenIcon';
import { newCurateTask } from './pages/CuratePage';
import { placeholderProgressData, ProgressBar } from './ProgressComponents';
import { ResizableSidebar, SidebarResizeEvent } from './ResizableSidebar';
import { SimpleButton } from './SimpleButton';
import { SplashScreen } from './SplashScreen';
import { TaskBar } from './TaskBar';
import { TitleBar } from './TitleBar';
import uuid = require('uuid');
import { ProgressData } from '../context/ProgressContext';
import { IWithShortcut } from 'react-keybind';
import { newGame } from '@shared/utils/misc';
import { cancelDialog, RANDOM_GAME_ROW_COUNT, resolveDialog, updateDialogField } from '@renderer/store/main/slice';
import { WithSearchProps } from '@renderer/containers/withSearch';
import { WithCurateProps } from '@renderer/containers/withCurateState';
import { WithFpfssProps } from '@renderer/containers/withFpfss';
import { WithViewProps } from '@renderer/containers/withView';
import { RequestState } from '@renderer/store/search/slice';

// Hide the right sidebar if the page is inside these paths
const hiddenRightSidebarPages = [Paths.ABOUT, Paths.CURATE, Paths.CONFIG, Paths.MANUAL, Paths.LOGS, Paths.TAGS, Paths.CATEGORIES];
Expand Down Expand Up @@ -663,8 +663,44 @@ export class App extends React.Component<AppProps> {
}
});
});
}

window.Shared.back.register(BackOut.FPFSS_ACTION, async (event, extId: string) => {
return new Promise((resolve, reject) => {
const previousConsent = getFpfssConsentExt(extId);
if (previousConsent) {
this.performFpfssAction(async (user) => {
resolve(user);
});
} else {
const msg = formatString(this.props.main.lang.dialog.extFpfssConsent, extId) as string;
remote.dialog.showMessageBox({
type: 'question',
title: 'FPFSS Extension Access',
message: msg,
buttons: [this.props.main.lang.misc.yes, this.props.main.lang.misc.no],
defaultId: 1,
cancelId: 1
})
.then(({ response }) => {
if (response === 0) {
this.performFpfssAction(async (user) => {
if (user) {
saveFpfssConsentExt(extId, true);
resolve(user);
} else {
reject(new Error('Launcher was unable to get FPFSS token'));
}
});
} else {
reject(new Error('User denied access to FPFSS token'));
}
}).catch((error) => {
reject(new Error('Failed to show FPFSS consent dialog: ' + error));
});
}
});
});
}

init() {
window.Shared.back.onStateChange = (state) => {
Expand Down Expand Up @@ -1185,7 +1221,7 @@ export class App extends React.Component<AppProps> {
buttons: ['Ok'],
};
if (error.code === 'ENOENT') {
opts.title = this.context.dialog.fileNotFound;
opts.title = this.props.main.lang.dialog.fileNotFound;
opts.message = (
'Failed to find the game file.\n' +
'If you are using Flashpoint Infinity, make sure you download the game first.\n'
Expand Down
Loading

0 comments on commit d0cecac

Please sign in to comment.