Pull request: 1163 safesearch http api vol.3
Merge in DNS/adguard-home from 1163-safesearch-1-3 to master Squashed commit of the following: commit f26c5fb4f7a27dc61b10c28d6672d5307796784c Merge:e7a1b885
143616ca
Author: Dimitry Kolyshev <dkolyshev@adguard.com> Date: Thu Mar 23 18:45:25 2023 +0700 Merge remote-tracking branch 'origin/master' into 1163-safesearch-1-3 # Conflicts: # CHANGELOG.md commite7a1b885d6
Merge:01b73d76
eb5d8a49
Author: Vladislav Abdulmyanov <v.abdulmyanov@adguard.com> Date: Wed Mar 22 13:55:23 2023 +0200 Merge branch '1163-safesearch-1-3' of ssh://bit.adguard.com:7999/dns/adguard-home into 1163-safesearch-1-3 commit01b73d763c
Author: Vladislav Abdulmyanov <v.abdulmyanov@adguard.com> Date: Wed Mar 22 13:52:02 2023 +0200 client: add safe search extended settings to clients commiteb5d8a499a
Author: Dimitry Kolyshev <dkolyshev@adguard.com> Date: Wed Mar 22 18:50:23 2023 +0700 all: docs commit 2043a8fba7f664ef365ccc5abac14a85035eb4b7 Author: Dimitry Kolyshev <dkolyshev@adguard.com> Date: Wed Mar 22 09:42:50 2023 +0700 all: docs commit bb1d2f6c0252891ccac3d3727eb23288a24d4bda Merge: 95f9fd3dc3edab43
Author: Dimitry Kolyshev <dkolyshev@adguard.com> Date: Wed Mar 22 09:42:00 2023 +0700 Merge remote-tracking branch 'origin/master' into 1163-safesearch-1-3 commit 95f9fd3dd1e8abcdf1a156e81aff8e52f320f4c3 Author: Vladislav Abdulmyanov <v.abdulmyanov@adguard.com> Date: Tue Mar 21 15:25:39 2023 +0200 client: move to new safe search api commit ac823a911f0d6ab6f1813d11a0ca082d54cc9131 Author: Dimitry Kolyshev <dkolyshev@adguard.com> Date: Mon Mar 20 22:40:29 2023 +0700 all: docs commit aaa287b125c7c7a775b821e0dd272199229a7538 Merge: 16fa703148431f8b
Author: Dimitry Kolyshev <dkolyshev@adguard.com> Date: Mon Mar 20 22:39:14 2023 +0700 Merge remote-tracking branch 'origin/master' into 1163-safesearch-1-3 commit 16fa7031ab2aec31139ace54ffa0155cde8e9135 Author: Dimitry Kolyshev <dkolyshev@adguard.com> Date: Mon Mar 20 22:39:03 2023 +0700 all: docs commit 498f7d3cbb842eda218b0fd06fc3bb3601b81f80 Author: Dimitry Kolyshev <dkolyshev@adguard.com> Date: Mon Mar 20 18:59:47 2023 +0700 filtering: imp code commit aab7b70e2355ba86577e5156c1d5569b21b4b358 Author: Dimitry Kolyshev <dkolyshev@adguard.com> Date: Mon Mar 20 18:40:18 2023 +0700 filtering: imp code commit d2870a18ffdb1d293993487073912168d6b75a38 Author: Dimitry Kolyshev <dkolyshev@adguard.com> Date: Fri Mar 17 21:57:58 2023 +0700 filtering: imp code commit 868f5d1ed29c3af702114079e7ffe46e136eb901 Author: Dimitry Kolyshev <dkolyshev@adguard.com> Date: Fri Mar 17 19:06:36 2023 +0700 all: imp docs commit f6d70b06ed873684501ce17f647ccf07a85dd50b Author: Dimitry Kolyshev <dkolyshev@adguard.com> Date: Fri Mar 17 19:05:40 2023 +0700 filtering: imp code commit 7cd9a37dde6262a8cf4f0f13f9946e011cc0e2cf Author: Dimitry Kolyshev <dkolyshev@adguard.com> Date: Thu Mar 16 14:56:51 2023 +0700 home: imp code commit 84d8817512e47a517ed2880ffa9dde5ffda1d288 Author: Dimitry Kolyshev <dkolyshev@adguard.com> Date: Thu Mar 16 09:39:41 2023 +0700 all: safesearch http api
This commit is contained in:
parent
143616ca6e
commit
df61741f60
13
CHANGELOG.md
13
CHANGELOG.md
|
@ -36,7 +36,7 @@ NOTE: Add new changes BELOW THIS COMMENT.
|
|||
- The ability to manage safesearch for each service by using the new
|
||||
`safe_search` field ([#1163]).
|
||||
|
||||
### Changed
|
||||
### Changed
|
||||
|
||||
- ARPA domain names containing a subnet within private networks now also
|
||||
considered private, behaving closer to [RFC 6761][rfc6761] ([#5567]).
|
||||
|
@ -90,6 +90,17 @@ In this release, the schema version has changed from 17 to 20.
|
|||
|
||||
### Deprecated
|
||||
|
||||
- The `POST /control/safesearch/enable` HTTP API is deprecated. Use the new
|
||||
`PUT /control/safesearch/settings` API.
|
||||
- The `POST /control/safesearch/disable` HTTP API is deprecated. Use the new
|
||||
`PUT /control/safesearch/settings` API
|
||||
- The `safesearch_enabled` field is deprecated in the following HTTP APIs:
|
||||
- `GET /control/clients`
|
||||
- `POST /control/clients/add`
|
||||
- `POST /control/clients/update`
|
||||
- `GET /control/clients/find?ip0=...&ip1=...&ip2=...`
|
||||
|
||||
Check `openapi/openapi.yaml` for more details.
|
||||
- The `GET /control/stats_info` HTTP API; use the new `GET
|
||||
/control/stats/config` API instead.
|
||||
|
||||
|
|
|
@ -167,6 +167,7 @@
|
|||
"enabled_parental_toast": "Enabled Parental Control",
|
||||
"disabled_safe_search_toast": "Disabled Safe Search",
|
||||
"enabled_save_search_toast": "Enabled Safe Search",
|
||||
"updated_save_search_toast": "Safe Search settings updated",
|
||||
"enabled_table_header": "Enabled",
|
||||
"name_table_header": "Name",
|
||||
"list_url_table_header": "List URL",
|
||||
|
|
|
@ -24,6 +24,12 @@ import { getFilteringStatus, setRules } from './filtering';
|
|||
export const toggleSettingStatus = createAction('SETTING_STATUS_TOGGLE');
|
||||
export const showSettingsFailure = createAction('SETTINGS_FAILURE_SHOW');
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {*} settingKey = SETTINGS_NAMES
|
||||
* @param {*} status: boolean | SafeSearchConfig
|
||||
* @returns
|
||||
*/
|
||||
export const toggleSetting = (settingKey, status) => async (dispatch) => {
|
||||
let successMessage = '';
|
||||
try {
|
||||
|
@ -49,14 +55,9 @@ export const toggleSetting = (settingKey, status) => async (dispatch) => {
|
|||
dispatch(toggleSettingStatus({ settingKey }));
|
||||
break;
|
||||
case SETTINGS_NAMES.safesearch:
|
||||
if (status) {
|
||||
successMessage = 'disabled_safe_search_toast';
|
||||
await apiClient.disableSafesearch();
|
||||
} else {
|
||||
successMessage = 'enabled_save_search_toast';
|
||||
await apiClient.enableSafesearch();
|
||||
}
|
||||
dispatch(toggleSettingStatus({ settingKey }));
|
||||
successMessage = 'updated_save_search_toast';
|
||||
await apiClient.updateSafesearch(status);
|
||||
dispatch(toggleSettingStatus({ settingKey, value: status }));
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
|
@ -71,7 +72,9 @@ export const initSettingsRequest = createAction('SETTINGS_INIT_REQUEST');
|
|||
export const initSettingsFailure = createAction('SETTINGS_INIT_FAILURE');
|
||||
export const initSettingsSuccess = createAction('SETTINGS_INIT_SUCCESS');
|
||||
|
||||
export const initSettings = (settingsList) => async (dispatch) => {
|
||||
export const initSettings = (settingsList = {
|
||||
safebrowsing: {}, parental: {},
|
||||
}) => async (dispatch) => {
|
||||
dispatch(initSettingsRequest());
|
||||
try {
|
||||
const safebrowsingStatus = await apiClient.getSafebrowsingStatus();
|
||||
|
@ -80,7 +83,6 @@ export const initSettings = (settingsList) => async (dispatch) => {
|
|||
const {
|
||||
safebrowsing,
|
||||
parental,
|
||||
safesearch,
|
||||
} = settingsList;
|
||||
const newSettingsList = {
|
||||
safebrowsing: {
|
||||
|
@ -92,8 +94,7 @@ export const initSettings = (settingsList) => async (dispatch) => {
|
|||
enabled: parentalStatus.enabled,
|
||||
},
|
||||
safesearch: {
|
||||
...safesearch,
|
||||
enabled: safesearchStatus.enabled,
|
||||
...safesearchStatus,
|
||||
},
|
||||
};
|
||||
dispatch(initSettingsSuccess({ settingsList: newSettingsList }));
|
||||
|
|
|
@ -208,24 +208,40 @@ class Api {
|
|||
// Safesearch
|
||||
SAFESEARCH_STATUS = { path: 'safesearch/status', method: 'GET' };
|
||||
|
||||
SAFESEARCH_ENABLE = { path: 'safesearch/enable', method: 'POST' };
|
||||
|
||||
SAFESEARCH_DISABLE = { path: 'safesearch/disable', method: 'POST' };
|
||||
SAFESEARCH_UPDATE = { path: 'safesearch/settings', method: 'PUT' };
|
||||
|
||||
getSafesearchStatus() {
|
||||
const { path, method } = this.SAFESEARCH_STATUS;
|
||||
return this.makeRequest(path, method);
|
||||
}
|
||||
|
||||
enableSafesearch() {
|
||||
const { path, method } = this.SAFESEARCH_ENABLE;
|
||||
return this.makeRequest(path, method);
|
||||
/**
|
||||
* interface SafeSearchConfig {
|
||||
"enabled": boolean,
|
||||
"bing": boolean,
|
||||
"duckduckgo": boolean,
|
||||
"google": boolean,
|
||||
"pixabay": boolean,
|
||||
"yandex": boolean,
|
||||
"youtube": boolean
|
||||
* }
|
||||
* @param {*} data - SafeSearchConfig
|
||||
* @returns 200 ok
|
||||
*/
|
||||
updateSafesearch(data) {
|
||||
const { path, method } = this.SAFESEARCH_UPDATE;
|
||||
return this.makeRequest(path, method, { data });
|
||||
}
|
||||
|
||||
disableSafesearch() {
|
||||
const { path, method } = this.SAFESEARCH_DISABLE;
|
||||
return this.makeRequest(path, method);
|
||||
}
|
||||
// enableSafesearch() {
|
||||
// const { path, method } = this.SAFESEARCH_ENABLE;
|
||||
// return this.makeRequest(path, method);
|
||||
// }
|
||||
|
||||
// disableSafesearch() {
|
||||
// const { path, method } = this.SAFESEARCH_DISABLE;
|
||||
// return this.makeRequest(path, method);
|
||||
// }
|
||||
|
||||
// Language
|
||||
|
||||
|
|
|
@ -7,6 +7,7 @@ import { useDispatch, useSelector } from 'react-redux';
|
|||
import ReactTable from 'react-table';
|
||||
|
||||
import { getAllBlockedServices } from '../../../../actions/services';
|
||||
import { initSettings } from '../../../../actions';
|
||||
import {
|
||||
splitByNewLine,
|
||||
countClientsStatistics,
|
||||
|
@ -38,9 +39,13 @@ const ClientsTable = ({
|
|||
const [t] = useTranslation();
|
||||
const dispatch = useDispatch();
|
||||
const services = useSelector((store) => store?.services);
|
||||
const globalSettings = useSelector((store) => store?.settings.settingsList) || {};
|
||||
|
||||
const { safesearch } = globalSettings;
|
||||
|
||||
useEffect(() => {
|
||||
dispatch(getAllBlockedServices());
|
||||
dispatch(initSettings());
|
||||
}, []);
|
||||
|
||||
const handleFormAdd = (values) => {
|
||||
|
@ -107,6 +112,7 @@ const ClientsTable = ({
|
|||
tags: [],
|
||||
use_global_settings: true,
|
||||
use_global_blocked_services: true,
|
||||
safe_search: { ...(safesearch || {}) },
|
||||
};
|
||||
};
|
||||
|
||||
|
|
|
@ -11,7 +11,7 @@ import Select from 'react-select';
|
|||
import i18n from '../../../i18n';
|
||||
import Tabs from '../../ui/Tabs';
|
||||
import Examples from '../Dns/Upstream/Examples';
|
||||
import { toggleAllServices, trimLinesAndRemoveEmpty } from '../../../helpers/helpers';
|
||||
import { toggleAllServices, trimLinesAndRemoveEmpty, captitalizeWords } from '../../../helpers/helpers';
|
||||
import {
|
||||
renderInputField,
|
||||
renderGroupField,
|
||||
|
@ -40,10 +40,6 @@ const settingsCheckboxes = [
|
|||
name: 'parental_enabled',
|
||||
placeholder: 'use_adguard_parental',
|
||||
},
|
||||
{
|
||||
name: 'safesearch_enabled',
|
||||
placeholder: 'enforce_safe_search',
|
||||
},
|
||||
];
|
||||
const validate = (values) => {
|
||||
const errors = {};
|
||||
|
@ -139,8 +135,12 @@ let Form = (props) => {
|
|||
processingUpdating,
|
||||
invalid,
|
||||
tagsOptions,
|
||||
initialValues,
|
||||
} = props;
|
||||
const services = useSelector((store) => store?.services);
|
||||
const { safe_search } = initialValues;
|
||||
const safeSearchServices = { ...safe_search };
|
||||
delete safeSearchServices.enabled;
|
||||
|
||||
const [activeTabLabel, setActiveTabLabel] = useState('settings');
|
||||
|
||||
|
@ -163,6 +163,28 @@ let Form = (props) => {
|
|||
/>
|
||||
</div>
|
||||
))}
|
||||
<div className="form__group">
|
||||
<Field
|
||||
name="safe_search.enabled"
|
||||
type="checkbox"
|
||||
component={CheckboxField}
|
||||
placeholder={t('enforce_safe_search')}
|
||||
disabled={useGlobalSettings}
|
||||
/>
|
||||
</div>
|
||||
<div className='form__group--inner'>
|
||||
{Object.keys(safeSearchServices).map((searchKey) => (
|
||||
<div key={searchKey}>
|
||||
<Field
|
||||
name={`safe_search.${searchKey}`}
|
||||
type="checkbox"
|
||||
component={CheckboxField}
|
||||
placeholder={captitalizeWords(searchKey)}
|
||||
disabled={useGlobalSettings}
|
||||
/>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>,
|
||||
},
|
||||
block_services: {
|
||||
|
@ -358,6 +380,7 @@ Form.propTypes = {
|
|||
processingUpdating: PropTypes.bool.isRequired,
|
||||
invalid: PropTypes.bool.isRequired,
|
||||
tagsOptions: PropTypes.array.isRequired,
|
||||
initialValues: PropTypes.object,
|
||||
};
|
||||
|
||||
const selector = formValueSelector(FORM_NAME.CLIENT);
|
||||
|
|
|
@ -10,7 +10,7 @@ import Checkbox from '../ui/Checkbox';
|
|||
import Loading from '../ui/Loading';
|
||||
import PageTitle from '../ui/PageTitle';
|
||||
import Card from '../ui/Card';
|
||||
import { getObjectKeysSorted } from '../../helpers/helpers';
|
||||
import { getObjectKeysSorted, captitalizeWords } from '../../helpers/helpers';
|
||||
import './Settings.css';
|
||||
|
||||
const ORDER_KEY = 'order';
|
||||
|
@ -28,12 +28,6 @@ const SETTINGS = {
|
|||
subtitle: 'use_adguard_parental_hint',
|
||||
[ORDER_KEY]: 1,
|
||||
},
|
||||
safesearch: {
|
||||
enabled: false,
|
||||
title: 'enforce_safe_search',
|
||||
subtitle: 'enforce_save_search_hint',
|
||||
[ORDER_KEY]: 2,
|
||||
},
|
||||
};
|
||||
|
||||
class Settings extends Component {
|
||||
|
@ -44,7 +38,7 @@ class Settings extends Component {
|
|||
this.props.getFilteringStatus();
|
||||
}
|
||||
|
||||
renderSettings = (settings) => getObjectKeysSorted(settings, ORDER_KEY)
|
||||
renderSettings = (settings) => getObjectKeysSorted(SETTINGS, ORDER_KEY)
|
||||
.map((key) => {
|
||||
const setting = settings[key];
|
||||
const { enabled } = setting;
|
||||
|
@ -55,6 +49,35 @@ class Settings extends Component {
|
|||
/>;
|
||||
});
|
||||
|
||||
renderSafeSearch = () => {
|
||||
const { settings: { settingsList: { safesearch } } } = this.props;
|
||||
const { enabled } = safesearch || {};
|
||||
const searches = { ...(safesearch || {}) };
|
||||
delete searches.enabled;
|
||||
return (
|
||||
<>
|
||||
<Checkbox
|
||||
enabled={enabled}
|
||||
title='enforce_safe_search'
|
||||
subtitle='enforce_save_search_hint'
|
||||
handleChange={({ target: { checked: enabled } }) => this.props.toggleSetting('safesearch', { ...safesearch, enabled })}
|
||||
/>
|
||||
<div className='form__group--inner'>
|
||||
{Object.keys(searches).map((searchKey) => (
|
||||
<Checkbox
|
||||
key={searchKey}
|
||||
enabled={searches[searchKey]}
|
||||
title={captitalizeWords(searchKey)}
|
||||
subtitle=''
|
||||
disabled={!safesearch.enabled}
|
||||
handleChange={({ target: { checked } }) => this.props.toggleSetting('safesearch', { ...safesearch, [searchKey]: checked })}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
render() {
|
||||
const {
|
||||
settings,
|
||||
|
@ -92,6 +115,7 @@ class Settings extends Component {
|
|||
setFiltersConfig={setFiltersConfig}
|
||||
/>
|
||||
{this.renderSettings(settings.settingsList)}
|
||||
{this.renderSafeSearch()}
|
||||
</div>
|
||||
</Card>
|
||||
</div>
|
||||
|
|
|
@ -11,13 +11,14 @@ class Checkbox extends Component {
|
|||
subtitle,
|
||||
enabled,
|
||||
handleChange,
|
||||
disabled,
|
||||
t,
|
||||
} = this.props;
|
||||
return (
|
||||
<div className="form__group form__group--checkbox">
|
||||
<label className="checkbox checkbox--settings">
|
||||
<span className="checkbox__marker"/>
|
||||
<input type="checkbox" className="checkbox__input" onChange={handleChange} checked={enabled}/>
|
||||
<input type="checkbox" className="checkbox__input" onChange={handleChange} checked={enabled} disabled={disabled}/>
|
||||
<span className="checkbox__label">
|
||||
<span className="checkbox__label-text">
|
||||
<span className="checkbox__label-title">{ t(title) }</span>
|
||||
|
@ -35,6 +36,7 @@ Checkbox.propTypes = {
|
|||
subtitle: PropTypes.string.isRequired,
|
||||
enabled: PropTypes.bool.isRequired,
|
||||
handleChange: PropTypes.func.isRequired,
|
||||
disabled: PropTypes.bool,
|
||||
t: PropTypes.func,
|
||||
};
|
||||
|
||||
|
|
|
@ -22,11 +22,11 @@ const settings = handleActions(
|
|||
},
|
||||
[actions.toggleSettingStatus]: (state, { payload }) => {
|
||||
const { settingsList } = state;
|
||||
const { settingKey } = payload;
|
||||
const { settingKey, value } = payload;
|
||||
|
||||
const setting = settingsList[settingKey];
|
||||
|
||||
const newSetting = {
|
||||
const newSetting = value || {
|
||||
...setting,
|
||||
enabled: !setting.enabled,
|
||||
};
|
||||
|
|
|
@ -461,6 +461,7 @@ func (d *DNSFilter) RegisterFilteringHandlers() {
|
|||
registerHTTP(http.MethodPost, "/control/safesearch/enable", d.handleSafeSearchEnable)
|
||||
registerHTTP(http.MethodPost, "/control/safesearch/disable", d.handleSafeSearchDisable)
|
||||
registerHTTP(http.MethodGet, "/control/safesearch/status", d.handleSafeSearchStatus)
|
||||
registerHTTP(http.MethodPut, "/control/safesearch/settings", d.handleSafeSearchSettings)
|
||||
|
||||
registerHTTP(http.MethodGet, "/control/rewrite/list", d.handleRewriteList)
|
||||
registerHTTP(http.MethodPost, "/control/rewrite/add", d.handleRewriteAdd)
|
||||
|
|
|
@ -17,7 +17,7 @@ type SafeSearch interface {
|
|||
// SafeSearchConfig is a struct with safe search related settings.
|
||||
type SafeSearchConfig struct {
|
||||
// CustomResolver is the resolver used by safe search.
|
||||
CustomResolver Resolver `yaml:"-"`
|
||||
CustomResolver Resolver `yaml:"-" json:"-"`
|
||||
|
||||
// Enabled indicates if safe search is enabled entirely.
|
||||
Enabled bool `yaml:"enabled" json:"enabled"`
|
||||
|
|
|
@ -1,29 +1,63 @@
|
|||
package filtering
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
|
||||
"github.com/AdguardTeam/AdGuardHome/internal/aghhttp"
|
||||
)
|
||||
|
||||
// TODO(d.kolyshev): Replace handlers below with the new API.
|
||||
|
||||
// handleSafeSearchEnable is the handler for POST /control/safesearch/enable
|
||||
// HTTP API.
|
||||
//
|
||||
// Deprecated: Use handleSafeSearchSettings.
|
||||
func (d *DNSFilter) handleSafeSearchEnable(w http.ResponseWriter, r *http.Request) {
|
||||
setProtectedBool(&d.confLock, &d.Config.SafeSearchConf.Enabled, true)
|
||||
d.Config.ConfigModified()
|
||||
}
|
||||
|
||||
// handleSafeSearchDisable is the handler for POST /control/safesearch/disable
|
||||
// HTTP API.
|
||||
//
|
||||
// Deprecated: Use handleSafeSearchSettings.
|
||||
func (d *DNSFilter) handleSafeSearchDisable(w http.ResponseWriter, r *http.Request) {
|
||||
setProtectedBool(&d.confLock, &d.Config.SafeSearchConf.Enabled, false)
|
||||
d.Config.ConfigModified()
|
||||
}
|
||||
|
||||
// handleSafeSearchStatus is the handler for GET /control/safesearch/status
|
||||
// HTTP API.
|
||||
func (d *DNSFilter) handleSafeSearchStatus(w http.ResponseWriter, r *http.Request) {
|
||||
resp := &struct {
|
||||
Enabled bool `json:"enabled"`
|
||||
}{
|
||||
Enabled: protectedBool(&d.confLock, &d.Config.SafeSearchConf.Enabled),
|
||||
}
|
||||
var resp SafeSearchConfig
|
||||
func() {
|
||||
d.confLock.RLock()
|
||||
defer d.confLock.RUnlock()
|
||||
|
||||
resp = d.Config.SafeSearchConf
|
||||
}()
|
||||
|
||||
_ = aghhttp.WriteJSONResponse(w, r, resp)
|
||||
}
|
||||
|
||||
// handleSafeSearchSettings is the handler for PUT /control/safesearch/settings
|
||||
// HTTP API.
|
||||
func (d *DNSFilter) handleSafeSearchSettings(w http.ResponseWriter, r *http.Request) {
|
||||
req := &SafeSearchConfig{}
|
||||
err := json.NewDecoder(r.Body).Decode(req)
|
||||
if err != nil {
|
||||
aghhttp.Error(r, w, http.StatusBadRequest, "reading req: %s", err)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func() {
|
||||
d.confLock.Lock()
|
||||
defer d.confLock.Unlock()
|
||||
|
||||
d.Config.SafeSearchConf = *req
|
||||
}()
|
||||
|
||||
d.Config.ConfigModified()
|
||||
|
||||
aghhttp.OK(w)
|
||||
}
|
||||
|
|
|
@ -27,7 +27,8 @@ type clientJSON struct {
|
|||
// the allowlist.
|
||||
DisallowedRule *string `json:"disallowed_rule,omitempty"`
|
||||
|
||||
WHOISInfo *RuntimeClientWHOISInfo `json:"whois_info,omitempty"`
|
||||
WHOISInfo *RuntimeClientWHOISInfo `json:"whois_info,omitempty"`
|
||||
SafeSearchConf *filtering.SafeSearchConfig `json:"safe_search"`
|
||||
|
||||
Name string `json:"name"`
|
||||
|
||||
|
@ -59,7 +60,7 @@ type clientListJSON struct {
|
|||
Tags []string `json:"supported_tags"`
|
||||
}
|
||||
|
||||
// respond with information about configured clients
|
||||
// handleGetClients is the handler for GET /control/clients HTTP API.
|
||||
func (clients *clientsContainer) handleGetClients(w http.ResponseWriter, r *http.Request) {
|
||||
data := clientListJSON{}
|
||||
|
||||
|
@ -88,32 +89,36 @@ func (clients *clientsContainer) handleGetClients(w http.ResponseWriter, r *http
|
|||
_ = aghhttp.WriteJSONResponse(w, r, data)
|
||||
}
|
||||
|
||||
// Convert JSON object to Client object
|
||||
// jsonToClient converts JSON object to Client object.
|
||||
func jsonToClient(cj clientJSON) (c *Client) {
|
||||
// TODO(d.kolyshev): Remove after cleaning the deprecated
|
||||
// [clientJSON.SafeSearchEnabled] field.
|
||||
safeSearchConf := filtering.SafeSearchConfig{Enabled: cj.SafeSearchEnabled}
|
||||
var safeSearchConf filtering.SafeSearchConfig
|
||||
if cj.SafeSearchConf != nil {
|
||||
safeSearchConf = *cj.SafeSearchConf
|
||||
} else {
|
||||
// TODO(d.kolyshev): Remove after cleaning the deprecated
|
||||
// [clientJSON.SafeSearchEnabled] field.
|
||||
safeSearchConf = filtering.SafeSearchConfig{Enabled: cj.SafeSearchEnabled}
|
||||
|
||||
// Set default service flags for enabled safesearch.
|
||||
if safeSearchConf.Enabled {
|
||||
safeSearchConf.Bing = true
|
||||
safeSearchConf.DuckDuckGo = true
|
||||
safeSearchConf.Google = true
|
||||
safeSearchConf.Pixabay = true
|
||||
safeSearchConf.Yandex = true
|
||||
safeSearchConf.YouTube = true
|
||||
// Set default service flags for enabled safesearch.
|
||||
if safeSearchConf.Enabled {
|
||||
safeSearchConf.Bing = true
|
||||
safeSearchConf.DuckDuckGo = true
|
||||
safeSearchConf.Google = true
|
||||
safeSearchConf.Pixabay = true
|
||||
safeSearchConf.Yandex = true
|
||||
safeSearchConf.YouTube = true
|
||||
}
|
||||
}
|
||||
|
||||
return &Client{
|
||||
Name: cj.Name,
|
||||
IDs: cj.IDs,
|
||||
Tags: cj.Tags,
|
||||
UseOwnSettings: !cj.UseGlobalSettings,
|
||||
FilteringEnabled: cj.FilteringEnabled,
|
||||
ParentalEnabled: cj.ParentalEnabled,
|
||||
safeSearchConf: safeSearchConf,
|
||||
SafeBrowsingEnabled: cj.SafeBrowsingEnabled,
|
||||
|
||||
Name: cj.Name,
|
||||
IDs: cj.IDs,
|
||||
Tags: cj.Tags,
|
||||
UseOwnSettings: !cj.UseGlobalSettings,
|
||||
FilteringEnabled: cj.FilteringEnabled,
|
||||
ParentalEnabled: cj.ParentalEnabled,
|
||||
SafeBrowsingEnabled: cj.SafeBrowsingEnabled,
|
||||
safeSearchConf: safeSearchConf,
|
||||
UseOwnBlockedServices: !cj.UseGlobalBlockedServices,
|
||||
BlockedServices: cj.BlockedServices,
|
||||
|
||||
|
@ -121,7 +126,7 @@ func jsonToClient(cj clientJSON) (c *Client) {
|
|||
}
|
||||
}
|
||||
|
||||
// Convert Client object to JSON
|
||||
// clientToJSON converts Client object to JSON.
|
||||
func clientToJSON(c *Client) (cj *clientJSON) {
|
||||
// TODO(d.kolyshev): Remove after cleaning the deprecated
|
||||
// [clientJSON.SafeSearchEnabled] field.
|
||||
|
@ -136,6 +141,7 @@ func clientToJSON(c *Client) (cj *clientJSON) {
|
|||
FilteringEnabled: c.FilteringEnabled,
|
||||
ParentalEnabled: c.ParentalEnabled,
|
||||
SafeSearchEnabled: safeSearchConf.Enabled,
|
||||
SafeSearchConf: safeSearchConf,
|
||||
SafeBrowsingEnabled: c.SafeBrowsingEnabled,
|
||||
|
||||
UseGlobalBlockedServices: !c.UseOwnBlockedServices,
|
||||
|
@ -145,7 +151,7 @@ func clientToJSON(c *Client) (cj *clientJSON) {
|
|||
}
|
||||
}
|
||||
|
||||
// Add a new client
|
||||
// handleAddClient is the handler for POST /control/clients/add HTTP API.
|
||||
func (clients *clientsContainer) handleAddClient(w http.ResponseWriter, r *http.Request) {
|
||||
cj := clientJSON{}
|
||||
err := json.NewDecoder(r.Body).Decode(&cj)
|
||||
|
@ -172,7 +178,7 @@ func (clients *clientsContainer) handleAddClient(w http.ResponseWriter, r *http.
|
|||
onConfigModified()
|
||||
}
|
||||
|
||||
// Remove client
|
||||
// handleDelClient is the handler for POST /control/clients/delete HTTP API.
|
||||
func (clients *clientsContainer) handleDelClient(w http.ResponseWriter, r *http.Request) {
|
||||
cj := clientJSON{}
|
||||
err := json.NewDecoder(r.Body).Decode(&cj)
|
||||
|
@ -202,7 +208,7 @@ type updateJSON struct {
|
|||
Data clientJSON `json:"data"`
|
||||
}
|
||||
|
||||
// Update client's properties
|
||||
// handleUpdateClient is the handler for POST /control/clients/update HTTP API.
|
||||
func (clients *clientsContainer) handleUpdateClient(w http.ResponseWriter, r *http.Request) {
|
||||
dj := updateJSON{}
|
||||
err := json.NewDecoder(r.Body).Decode(&dj)
|
||||
|
@ -229,7 +235,7 @@ func (clients *clientsContainer) handleUpdateClient(w http.ResponseWriter, r *ht
|
|||
onConfigModified()
|
||||
}
|
||||
|
||||
// Get the list of clients by IP address list
|
||||
// handleFindClient is the handler for GET /control/clients/find HTTP API.
|
||||
func (clients *clientsContainer) handleFindClient(w http.ResponseWriter, r *http.Request) {
|
||||
q := r.URL.Query()
|
||||
data := []map[string]*clientJSON{}
|
||||
|
|
|
@ -83,6 +83,78 @@ accept and return a JSON object with the following format:
|
|||
|
||||
|
||||
|
||||
## v0.107.27: API changes
|
||||
|
||||
### Deprecated HTTP APIs
|
||||
|
||||
The following HTTP APIs are deprecated:
|
||||
|
||||
* `POST /control/safesearch/enable` is deprecated. Use the new
|
||||
`PUT /control/safesearch/settings`.
|
||||
|
||||
* `POST /control/safesearch/disable` is deprecated. Use the new
|
||||
`PUT /control/safesearch/settings`.
|
||||
|
||||
### New HTTP API `PUT /control/safesearch/settings`
|
||||
|
||||
* The new `PUT /control/safesearch/settings` HTTP API allows safesearch
|
||||
settings updates. It accepts a JSON object with the following format:
|
||||
|
||||
```json
|
||||
{
|
||||
"enabled": true,
|
||||
"bing": false,
|
||||
"duckduckgo": true,
|
||||
"google": false,
|
||||
"pixabay": false,
|
||||
"yandex": true,
|
||||
"youtube": false
|
||||
}
|
||||
```
|
||||
|
||||
### `GET /control/safesearch/status`
|
||||
|
||||
* The `control/safesearch/status` HTTP API has been changed. It now returns a
|
||||
JSON object with the following format:
|
||||
|
||||
```json
|
||||
{
|
||||
"enabled": true,
|
||||
"bing": false,
|
||||
"duckduckgo": true,
|
||||
"google": false,
|
||||
"pixabay": false,
|
||||
"yandex": true,
|
||||
"youtube": false
|
||||
}
|
||||
```
|
||||
|
||||
### `/control/clients` HTTP APIs
|
||||
|
||||
The following HTTP APIs have been changed:
|
||||
|
||||
* `GET /control/clients`;
|
||||
* `GET /control/clients/find?ip0=...&ip1=...&ip2=...`;
|
||||
* `POST /control/clients/add`;
|
||||
* `POST /control/clients/update`;
|
||||
|
||||
The `safesearch_enabled` field is deprecated. The new field `safe_search` has
|
||||
been added to JSON objects. It has the following format:
|
||||
|
||||
```json
|
||||
{
|
||||
"enabled": true,
|
||||
"bing": false,
|
||||
"duckduckgo": true,
|
||||
"google": false,
|
||||
"pixabay": false,
|
||||
"yandex": true,
|
||||
"youtube": false
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
## v0.107.23: API changes
|
||||
|
||||
### Experimental “beta” APIs removed
|
||||
|
|
|
@ -795,6 +795,7 @@
|
|||
'sensitivity': 13
|
||||
'/safesearch/enable':
|
||||
'post':
|
||||
'deprecated': true
|
||||
'tags':
|
||||
- 'safesearch'
|
||||
'operationId': 'safesearchEnable'
|
||||
|
@ -804,6 +805,7 @@
|
|||
'description': 'OK.'
|
||||
'/safesearch/disable':
|
||||
'post':
|
||||
'deprecated': true
|
||||
'tags':
|
||||
- 'safesearch'
|
||||
'operationId': 'safesearchDisable'
|
||||
|
@ -811,6 +813,20 @@
|
|||
'responses':
|
||||
'200':
|
||||
'description': 'OK.'
|
||||
'/safesearch/settings':
|
||||
'put':
|
||||
'tags':
|
||||
- 'safesearch'
|
||||
'operationId': 'safesearchSettings'
|
||||
'summary': 'Update safesearch settings'
|
||||
'requestBody':
|
||||
'content':
|
||||
'application/json':
|
||||
'schema':
|
||||
'$ref': '#/components/schemas/SafeSearchConfig'
|
||||
'responses':
|
||||
'200':
|
||||
'description': 'OK.'
|
||||
'/safesearch/status':
|
||||
'get':
|
||||
'tags':
|
||||
|
@ -823,14 +839,7 @@
|
|||
'content':
|
||||
'application/json':
|
||||
'schema':
|
||||
'type': 'object'
|
||||
'properties':
|
||||
'enabled':
|
||||
'type': 'boolean'
|
||||
'examples':
|
||||
'response':
|
||||
'value':
|
||||
'enabled': false
|
||||
'$ref': '#/components/schemas/SafeSearchConfig'
|
||||
'/clients':
|
||||
'get':
|
||||
'tags':
|
||||
|
@ -2394,6 +2403,24 @@
|
|||
- 'name'
|
||||
- 'language'
|
||||
- 'theme'
|
||||
'SafeSearchConfig':
|
||||
'type': 'object'
|
||||
'description': 'Safe search settings.'
|
||||
'properties':
|
||||
'enabled':
|
||||
'type': 'boolean'
|
||||
'bing':
|
||||
'type': 'boolean'
|
||||
'duckduckgo':
|
||||
'type': 'boolean'
|
||||
'google':
|
||||
'type': 'boolean'
|
||||
'pixabay':
|
||||
'type': 'boolean'
|
||||
'yandex':
|
||||
'type': 'boolean'
|
||||
'youtube':
|
||||
'type': 'boolean'
|
||||
'Client':
|
||||
'type': 'object'
|
||||
'description': 'Client information.'
|
||||
|
@ -2416,7 +2443,10 @@
|
|||
'safebrowsing_enabled':
|
||||
'type': 'boolean'
|
||||
'safesearch_enabled':
|
||||
'deprecated': true
|
||||
'type': 'boolean'
|
||||
'safe_search':
|
||||
'$ref': '#/components/schemas/SafeSearchConfig'
|
||||
'use_global_blocked_services':
|
||||
'type': 'boolean'
|
||||
'blocked_services':
|
||||
|
@ -2477,6 +2507,7 @@
|
|||
'parental_enabled': true
|
||||
'safebrowsing_enabled': true
|
||||
'safesearch_enabled': true
|
||||
'safe_search': {}
|
||||
'use_global_blocked_services': true
|
||||
'blocked_services': null
|
||||
'upstreams': null
|
||||
|
@ -2491,6 +2522,7 @@
|
|||
'parental_enabled': true
|
||||
'safebrowsing_enabled': true
|
||||
'safesearch_enabled': true
|
||||
'safe_search': {}
|
||||
'use_global_blocked_services': true
|
||||
'blocked_services': null
|
||||
'upstreams': null
|
||||
|
@ -2551,7 +2583,10 @@
|
|||
'safebrowsing_enabled':
|
||||
'type': 'boolean'
|
||||
'safesearch_enabled':
|
||||
'deprecated': true
|
||||
'type': 'boolean'
|
||||
'safe_search':
|
||||
'$ref': '#/components/schemas/SafeSearchConfig'
|
||||
'use_global_blocked_services':
|
||||
'type': 'boolean'
|
||||
'blocked_services':
|
||||
|
|
Loading…
Reference in New Issue