Merge: * API: Revert meaningless incompatible changes
Close #1067 * commit '1583262df180006e70112c74373de3f39bfcb11b': - client: rename helper + client: use search params for querylog request * openapi: minor * API changes
This commit is contained in:
commit
dbe57969f1
|
@ -1044,20 +1044,14 @@ We store data for a limited amount of time - the log file is automatically rotat
|
||||||
|
|
||||||
Request:
|
Request:
|
||||||
|
|
||||||
POST /control/querylog
|
GET /control/querylog
|
||||||
|
?older_than=2006-01-02T15:04:05.999999999Z07:00
|
||||||
|
&filter_domain=...
|
||||||
|
&filter_client=...
|
||||||
|
&filter_question_type=A | AAAA
|
||||||
|
&filter_response_status= | filtered
|
||||||
|
|
||||||
{
|
If `older_than` value is set, server returns the next chunk of entries that are older than this time stamp. This setting is used for paging. UI sets the empty value on the first request and gets the latest log entries. To get the older entries, UI sets this value to the timestamp of the last (the oldest) entry from the previous response from Server.
|
||||||
older_than: "2006-01-02T15:04:05.999999999Z07:00" // must be "" for the first request
|
|
||||||
|
|
||||||
filter:{
|
|
||||||
domain: "..."
|
|
||||||
client: "..."
|
|
||||||
question_type: "A" | "AAAA"
|
|
||||||
response_status: "" | "filtered"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
If `older_than` value is set, server returns the next chunk of entries that are older than this time stamp. This setting is used for paging. UI sets this value to `""` on the first request and gets the latest log entries. To get the older entries, UI sets this value to the timestamp of the last (the oldest) entry from the previous response from Server.
|
|
||||||
|
|
||||||
If "filter" settings are set, server returns only entries that match the specified request.
|
If "filter" settings are set, server returns only entries that match the specified request.
|
||||||
|
|
||||||
|
@ -1143,7 +1137,7 @@ As a result of the update procedure, all enabled filter files are written to dis
|
||||||
|
|
||||||
Request:
|
Request:
|
||||||
|
|
||||||
GET /control/filtering_info
|
GET /control/filtering/status
|
||||||
|
|
||||||
Response:
|
Response:
|
||||||
|
|
||||||
|
@ -1171,7 +1165,7 @@ Response:
|
||||||
|
|
||||||
Request:
|
Request:
|
||||||
|
|
||||||
POST /control/filtering_config
|
POST /control/filtering/config
|
||||||
|
|
||||||
{
|
{
|
||||||
"enabled": true | false
|
"enabled": true | false
|
||||||
|
|
|
@ -12725,6 +12725,11 @@
|
||||||
"requires-port": "^1.0.0"
|
"requires-port": "^1.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"url-polyfill": {
|
||||||
|
"version": "1.1.7",
|
||||||
|
"resolved": "https://registry.npmjs.org/url-polyfill/-/url-polyfill-1.1.7.tgz",
|
||||||
|
"integrity": "sha512-ZrAxYWCREjmMtL8gSbSiKKLZZticgihCvVBtrFbUVpyoETt8GQJeG2okMWA8XryDAaHMjJfhnc+rnhXRbI4DXA=="
|
||||||
|
},
|
||||||
"use": {
|
"use": {
|
||||||
"version": "3.1.1",
|
"version": "3.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/use/-/use-3.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/use/-/use-3.1.1.tgz",
|
||||||
|
|
|
@ -33,7 +33,8 @@
|
||||||
"redux-actions": "^2.4.0",
|
"redux-actions": "^2.4.0",
|
||||||
"redux-form": "^7.4.2",
|
"redux-form": "^7.4.2",
|
||||||
"redux-thunk": "^2.3.0",
|
"redux-thunk": "^2.3.0",
|
||||||
"svg-url-loader": "^2.3.2"
|
"svg-url-loader": "^2.3.2",
|
||||||
|
"url-polyfill": "^1.1.7"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"autoprefixer": "^8.6.3",
|
"autoprefixer": "^8.6.3",
|
||||||
|
|
|
@ -15,7 +15,7 @@ export const getLogs = config => async (dispatch) => {
|
||||||
dispatch(getLogsRequest());
|
dispatch(getLogsRequest());
|
||||||
try {
|
try {
|
||||||
const { filter, lastRowTime: older_than } = config;
|
const { filter, lastRowTime: older_than } = config;
|
||||||
const logs = normalizeLogs(await apiClient.getQueryLog({ filter, older_than }));
|
const logs = normalizeLogs(await apiClient.getQueryLog({ ...filter, older_than }));
|
||||||
dispatch(getLogsSuccess({ logs, ...config }));
|
dispatch(getLogsSuccess({ logs, ...config }));
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
dispatch(addErrorToast({ error }));
|
dispatch(addErrorToast({ error }));
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
import axios from 'axios';
|
import axios from 'axios';
|
||||||
|
|
||||||
|
import { getPathWithQueryString } from '../helpers/helpers';
|
||||||
|
|
||||||
class Api {
|
class Api {
|
||||||
baseUrl = 'control';
|
baseUrl = 'control';
|
||||||
|
|
||||||
|
@ -90,16 +92,16 @@ class Api {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Filtering
|
// Filtering
|
||||||
FILTERING_INFO = { path: 'filtering_info', method: 'GET' };
|
FILTERING_STATUS = { path: 'filtering/status', method: 'GET' };
|
||||||
FILTERING_ADD_FILTER = { path: 'filtering/add_url', method: 'POST' };
|
FILTERING_ADD_FILTER = { path: 'filtering/add_url', method: 'POST' };
|
||||||
FILTERING_REMOVE_FILTER = { path: 'filtering/remove_url', method: 'POST' };
|
FILTERING_REMOVE_FILTER = { path: 'filtering/remove_url', method: 'POST' };
|
||||||
FILTERING_SET_RULES = { path: 'filtering/set_rules', method: 'POST' };
|
FILTERING_SET_RULES = { path: 'filtering/set_rules', method: 'POST' };
|
||||||
FILTERING_REFRESH = { path: 'filtering/refresh', method: 'POST' };
|
FILTERING_REFRESH = { path: 'filtering/refresh', method: 'POST' };
|
||||||
FILTERING_SET_URL = { path: 'filtering/set_url', method: 'POST' };
|
FILTERING_SET_URL = { path: 'filtering/set_url', method: 'POST' };
|
||||||
FILTERING_CONFIG = { path: 'filtering_config', method: 'POST' };
|
FILTERING_CONFIG = { path: 'filtering/config', method: 'POST' };
|
||||||
|
|
||||||
getFilteringStatus() {
|
getFilteringStatus() {
|
||||||
const { path, method } = this.FILTERING_INFO;
|
const { path, method } = this.FILTERING_STATUS;
|
||||||
return this.makeRequest(path, method);
|
return this.makeRequest(path, method);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -482,18 +484,15 @@ class Api {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Query log
|
// Query log
|
||||||
GET_QUERY_LOG = { path: 'querylog', method: 'POST' };
|
GET_QUERY_LOG = { path: 'querylog', method: 'GET' };
|
||||||
QUERY_LOG_CONFIG = { path: 'querylog_config', method: 'POST' };
|
QUERY_LOG_CONFIG = { path: 'querylog_config', method: 'POST' };
|
||||||
QUERY_LOG_INFO = { path: 'querylog_info', method: 'GET' };
|
QUERY_LOG_INFO = { path: 'querylog_info', method: 'GET' };
|
||||||
QUERY_LOG_CLEAR = { path: 'querylog_clear', method: 'POST' };
|
QUERY_LOG_CLEAR = { path: 'querylog_clear', method: 'POST' };
|
||||||
|
|
||||||
getQueryLog(data) {
|
getQueryLog(params) {
|
||||||
const { path, method } = this.GET_QUERY_LOG;
|
const { path, method } = this.GET_QUERY_LOG;
|
||||||
const config = {
|
const url = getPathWithQueryString(path, params);
|
||||||
data,
|
return this.makeRequest(url, method);
|
||||||
headers: { 'Content-Type': 'application/json' },
|
|
||||||
};
|
|
||||||
return this.makeRequest(path, method, config);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
getQueryLogInfo() {
|
getQueryLogInfo() {
|
||||||
|
|
|
@ -255,10 +255,10 @@ class Logs extends Component {
|
||||||
} = filteredObj;
|
} = filteredObj;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
domain: domain || '',
|
filter_domain: domain || '',
|
||||||
client: client || '',
|
filter_client: client || '',
|
||||||
question_type: isValidQuestionType(type) ? type.toUpperCase() : '',
|
filter_question_type: isValidQuestionType(type) ? type.toUpperCase() : '',
|
||||||
response_status: response === RESPONSE_FILTER.FILTERED ? response : '',
|
filter_response_status: response === RESPONSE_FILTER.FILTERED ? response : '',
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -372,8 +372,8 @@ export const DNS_RECORD_TYPES = [
|
||||||
];
|
];
|
||||||
|
|
||||||
export const DEFAULT_LOGS_FILTER = {
|
export const DEFAULT_LOGS_FILTER = {
|
||||||
domain: '',
|
filter_domain: '',
|
||||||
client: '',
|
filter_client: '',
|
||||||
question_type: '',
|
filter_question_type: '',
|
||||||
response_status: '',
|
filter_response_status: '',
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
import 'url-polyfill';
|
||||||
import dateParse from 'date-fns/parse';
|
import dateParse from 'date-fns/parse';
|
||||||
import dateFormat from 'date-fns/format';
|
import dateFormat from 'date-fns/format';
|
||||||
import subHours from 'date-fns/sub_hours';
|
import subHours from 'date-fns/sub_hours';
|
||||||
|
@ -321,3 +322,9 @@ export const normalizeWhois = (whois) => {
|
||||||
};
|
};
|
||||||
|
|
||||||
export const isValidQuestionType = type => type && DNS_RECORD_TYPES.includes(type.toUpperCase());
|
export const isValidQuestionType = type => type && DNS_RECORD_TYPES.includes(type.toUpperCase());
|
||||||
|
|
||||||
|
export const getPathWithQueryString = (path, params) => {
|
||||||
|
const searchParams = new URLSearchParams(params);
|
||||||
|
|
||||||
|
return `${path}?${searchParams.toString()}`;
|
||||||
|
};
|
||||||
|
|
|
@ -204,7 +204,7 @@ type filteringConfig struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get filtering configuration
|
// Get filtering configuration
|
||||||
func handleFilteringInfo(w http.ResponseWriter, r *http.Request) {
|
func handleFilteringStatus(w http.ResponseWriter, r *http.Request) {
|
||||||
resp := filteringConfig{}
|
resp := filteringConfig{}
|
||||||
config.RLock()
|
config.RLock()
|
||||||
resp.Enabled = config.DNS.FilteringEnabled
|
resp.Enabled = config.DNS.FilteringEnabled
|
||||||
|
@ -261,8 +261,8 @@ func handleFilteringConfig(w http.ResponseWriter, r *http.Request) {
|
||||||
|
|
||||||
// RegisterFilteringHandlers - register handlers
|
// RegisterFilteringHandlers - register handlers
|
||||||
func RegisterFilteringHandlers() {
|
func RegisterFilteringHandlers() {
|
||||||
httpRegister(http.MethodGet, "/control/filtering_info", handleFilteringInfo)
|
httpRegister(http.MethodGet, "/control/filtering/status", handleFilteringStatus)
|
||||||
httpRegister(http.MethodPost, "/control/filtering_config", handleFilteringConfig)
|
httpRegister(http.MethodPost, "/control/filtering/config", handleFilteringConfig)
|
||||||
httpRegister(http.MethodPost, "/control/filtering/add_url", handleFilteringAddURL)
|
httpRegister(http.MethodPost, "/control/filtering/add_url", handleFilteringAddURL)
|
||||||
httpRegister(http.MethodPost, "/control/filtering/remove_url", handleFilteringRemoveURL)
|
httpRegister(http.MethodPost, "/control/filtering/remove_url", handleFilteringRemoveURL)
|
||||||
httpRegister(http.MethodPost, "/control/filtering/set_url", handleFilteringSetURL)
|
httpRegister(http.MethodPost, "/control/filtering/set_url", handleFilteringSetURL)
|
||||||
|
|
|
@ -2,7 +2,7 @@ swagger: '2.0'
|
||||||
info:
|
info:
|
||||||
title: 'AdGuard Home'
|
title: 'AdGuard Home'
|
||||||
description: 'AdGuard Home REST API. Admin web interface is built on top of this REST API.'
|
description: 'AdGuard Home REST API. Admin web interface is built on top of this REST API.'
|
||||||
version: 0.98.1
|
version: '0.99'
|
||||||
schemes:
|
schemes:
|
||||||
- http
|
- http
|
||||||
basePath: /control
|
basePath: /control
|
||||||
|
@ -176,16 +176,34 @@ paths:
|
||||||
# --------------------------------------------------
|
# --------------------------------------------------
|
||||||
|
|
||||||
/querylog:
|
/querylog:
|
||||||
post:
|
get:
|
||||||
tags:
|
tags:
|
||||||
- log
|
- log
|
||||||
operationId: queryLog
|
operationId: queryLog
|
||||||
summary: 'Get DNS server query log'
|
summary: 'Get DNS server query log'
|
||||||
parameters:
|
parameters:
|
||||||
- in: "body"
|
- name: older_than
|
||||||
name: "body"
|
in: query
|
||||||
schema:
|
type: string
|
||||||
$ref: '#/definitions/QueryLogRequest'
|
- name: filter_domain
|
||||||
|
in: query
|
||||||
|
type: string
|
||||||
|
description: "Filter by domain name"
|
||||||
|
- name: filter_client
|
||||||
|
in: query
|
||||||
|
type: string
|
||||||
|
description: "Filter by client"
|
||||||
|
- name: filter_question_type
|
||||||
|
in: query
|
||||||
|
type: string
|
||||||
|
description: "Filter by question type"
|
||||||
|
- name: filter_response_status
|
||||||
|
in: query
|
||||||
|
type: string
|
||||||
|
description: "Filter by response status"
|
||||||
|
enum:
|
||||||
|
-
|
||||||
|
- filtered
|
||||||
responses:
|
responses:
|
||||||
200:
|
200:
|
||||||
description: OK
|
description: OK
|
||||||
|
@ -268,7 +286,6 @@ paths:
|
||||||
description: OK
|
description: OK
|
||||||
schema:
|
schema:
|
||||||
$ref: "#/definitions/StatsConfig"
|
$ref: "#/definitions/StatsConfig"
|
||||||
description: OK
|
|
||||||
|
|
||||||
/stats_config:
|
/stats_config:
|
||||||
post:
|
post:
|
||||||
|
@ -438,19 +455,19 @@ paths:
|
||||||
# Filtering status methods
|
# Filtering status methods
|
||||||
# --------------------------------------------------
|
# --------------------------------------------------
|
||||||
|
|
||||||
/filtering_info:
|
/filtering/status:
|
||||||
get:
|
get:
|
||||||
tags:
|
tags:
|
||||||
- filtering
|
- filtering
|
||||||
operationId: filteringInfo
|
operationId: filteringStatus
|
||||||
summary: 'Get filtering parameters'
|
summary: 'Get filtering parameters'
|
||||||
responses:
|
responses:
|
||||||
200:
|
200:
|
||||||
description: OK
|
description: OK
|
||||||
schema:
|
schema:
|
||||||
$ref: "#/definitions/FilterInfo"
|
$ref: "#/definitions/FilterStatus"
|
||||||
|
|
||||||
/filtering_config:
|
/filtering/config:
|
||||||
post:
|
post:
|
||||||
tags:
|
tags:
|
||||||
- filtering
|
- filtering
|
||||||
|
@ -534,13 +551,6 @@ paths:
|
||||||
This should work as intended, a `force` parameter is offered as last-resort attempt to make filter lists fresh.
|
This should work as intended, a `force` parameter is offered as last-resort attempt to make filter lists fresh.
|
||||||
|
|
||||||
If you ever find yourself using `force` to make something work that otherwise wont, this is a bug and report it accordingly.
|
If you ever find yourself using `force` to make something work that otherwise wont, this is a bug and report it accordingly.
|
||||||
|
|
||||||
parameters:
|
|
||||||
-
|
|
||||||
name: force
|
|
||||||
in: query
|
|
||||||
type: boolean
|
|
||||||
description: 'If any value is set, ignore cache and force re-download of all filters'
|
|
||||||
responses:
|
responses:
|
||||||
200:
|
200:
|
||||||
description: OK with how many filters were actually updated
|
description: OK with how many filters were actually updated
|
||||||
|
@ -1063,7 +1073,7 @@ definitions:
|
||||||
type: "string"
|
type: "string"
|
||||||
example: "https://adguardteam.github.io/AdGuardSDNSFilter/Filters/filter.txt"
|
example: "https://adguardteam.github.io/AdGuardSDNSFilter/Filters/filter.txt"
|
||||||
|
|
||||||
FilterInfo:
|
FilterStatus:
|
||||||
type: "object"
|
type: "object"
|
||||||
description: "Filtering settings"
|
description: "Filtering settings"
|
||||||
properties:
|
properties:
|
||||||
|
@ -1400,14 +1410,6 @@ definitions:
|
||||||
items:
|
items:
|
||||||
$ref: "#/definitions/QueryLogItem"
|
$ref: "#/definitions/QueryLogItem"
|
||||||
|
|
||||||
QueryLogRequest:
|
|
||||||
type: "object"
|
|
||||||
description: "Query log request data"
|
|
||||||
properties:
|
|
||||||
offset:
|
|
||||||
type: "integer"
|
|
||||||
example: 1234
|
|
||||||
|
|
||||||
QueryLogConfig:
|
QueryLogConfig:
|
||||||
type: "object"
|
type: "object"
|
||||||
description: "Query log configuration"
|
description: "Query log configuration"
|
||||||
|
|
|
@ -18,16 +18,12 @@ func httpError(r *http.Request, w http.ResponseWriter, code int, format string,
|
||||||
http.Error(w, text, code)
|
http.Error(w, text, code)
|
||||||
}
|
}
|
||||||
|
|
||||||
type filterJSON struct {
|
|
||||||
Domain string `json:"domain"`
|
|
||||||
Client string `json:"client"`
|
|
||||||
QuestionType string `json:"question_type"`
|
|
||||||
ResponseStatus string `json:"response_status"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type request struct {
|
type request struct {
|
||||||
OlderThan string `json:"older_than"`
|
olderThan string
|
||||||
Filter filterJSON `json:"filter"`
|
filterDomain string
|
||||||
|
filterClient string
|
||||||
|
filterQuestionType string
|
||||||
|
filterResponseStatus string
|
||||||
}
|
}
|
||||||
|
|
||||||
// "value" -> value, return TRUE
|
// "value" -> value, return TRUE
|
||||||
|
@ -41,20 +37,22 @@ func getDoubleQuotesEnclosedValue(s *string) bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (l *queryLog) handleQueryLog(w http.ResponseWriter, r *http.Request) {
|
func (l *queryLog) handleQueryLog(w http.ResponseWriter, r *http.Request) {
|
||||||
|
var err error
|
||||||
req := request{}
|
req := request{}
|
||||||
err := json.NewDecoder(r.Body).Decode(&req)
|
q := r.URL.Query()
|
||||||
if err != nil {
|
req.olderThan = q.Get("older_than")
|
||||||
httpError(r, w, http.StatusBadRequest, "json decode: %s", err)
|
req.filterDomain = q.Get("filter_domain")
|
||||||
return
|
req.filterClient = q.Get("filter_client")
|
||||||
}
|
req.filterQuestionType = q.Get("filter_question_type")
|
||||||
|
req.filterResponseStatus = q.Get("filter_response_status")
|
||||||
|
|
||||||
params := getDataParams{
|
params := getDataParams{
|
||||||
Domain: req.Filter.Domain,
|
Domain: req.filterDomain,
|
||||||
Client: req.Filter.Client,
|
Client: req.filterClient,
|
||||||
ResponseStatus: responseStatusAll,
|
ResponseStatus: responseStatusAll,
|
||||||
}
|
}
|
||||||
if len(req.OlderThan) != 0 {
|
if len(req.olderThan) != 0 {
|
||||||
params.OlderThan, err = time.Parse(time.RFC3339Nano, req.OlderThan)
|
params.OlderThan, err = time.Parse(time.RFC3339Nano, req.olderThan)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
httpError(r, w, http.StatusBadRequest, "invalid time stamp: %s", err)
|
httpError(r, w, http.StatusBadRequest, "invalid time stamp: %s", err)
|
||||||
return
|
return
|
||||||
|
@ -68,8 +66,8 @@ func (l *queryLog) handleQueryLog(w http.ResponseWriter, r *http.Request) {
|
||||||
params.StrictMatchClient = true
|
params.StrictMatchClient = true
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(req.Filter.QuestionType) != 0 {
|
if len(req.filterQuestionType) != 0 {
|
||||||
qtype, ok := dns.StringToType[req.Filter.QuestionType]
|
qtype, ok := dns.StringToType[req.filterQuestionType]
|
||||||
if !ok {
|
if !ok {
|
||||||
httpError(r, w, http.StatusBadRequest, "invalid question_type")
|
httpError(r, w, http.StatusBadRequest, "invalid question_type")
|
||||||
return
|
return
|
||||||
|
@ -77,8 +75,8 @@ func (l *queryLog) handleQueryLog(w http.ResponseWriter, r *http.Request) {
|
||||||
params.QuestionType = qtype
|
params.QuestionType = qtype
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(req.Filter.ResponseStatus) != 0 {
|
if len(req.filterResponseStatus) != 0 {
|
||||||
switch req.Filter.ResponseStatus {
|
switch req.filterResponseStatus {
|
||||||
case "filtered":
|
case "filtered":
|
||||||
params.ResponseStatus = responseStatusFiltered
|
params.ResponseStatus = responseStatusFiltered
|
||||||
default:
|
default:
|
||||||
|
@ -155,7 +153,7 @@ func (l *queryLog) handleQueryLogConfig(w http.ResponseWriter, r *http.Request)
|
||||||
|
|
||||||
// Register web handlers
|
// Register web handlers
|
||||||
func (l *queryLog) initWeb() {
|
func (l *queryLog) initWeb() {
|
||||||
l.conf.HTTPRegister("POST", "/control/querylog", l.handleQueryLog)
|
l.conf.HTTPRegister("GET", "/control/querylog", l.handleQueryLog)
|
||||||
l.conf.HTTPRegister("GET", "/control/querylog_info", l.handleQueryLogInfo)
|
l.conf.HTTPRegister("GET", "/control/querylog_info", l.handleQueryLogInfo)
|
||||||
l.conf.HTTPRegister("POST", "/control/querylog_clear", l.handleQueryLogClear)
|
l.conf.HTTPRegister("POST", "/control/querylog_clear", l.handleQueryLogClear)
|
||||||
l.conf.HTTPRegister("POST", "/control/querylog_config", l.handleQueryLogConfig)
|
l.conf.HTTPRegister("POST", "/control/querylog_config", l.handleQueryLogConfig)
|
||||||
|
|
Loading…
Reference in New Issue