1989 lines
211 KiB
HTML
1989 lines
211 KiB
HTML
|
<!DOCTYPE html><html lang="fr">
|
|||
|
<head><meta charset="utf-8">
|
|||
|
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
|||
|
<meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no"><title>utiliser-son-android-de-facon-plus-securisee - YannStatic</title>
|
|||
|
|
|||
|
<meta name="description" content="URL: https://linuxfr.org/news/utiliser-son-android-de-facon-plus-securiseeTitle: Utiliser son Android de façon plus sécuriséeAuthors: voxdemonix ...">
|
|||
|
<link rel="canonical" href="https://static.rnmkcy.eu/2019/12/25/utiliser-son-android-de-facon-plus-securisee.html"><link rel="alternate" type="application/rss+xml" title="YannStatic" href="/feed.xml">
|
|||
|
|
|||
|
<!-- - include head/favicon.html - -->
|
|||
|
<link rel="shortcut icon" type="image/png" href="/assets/favicon/favicon.png"><link rel="stylesheet" href="/assets/css/main.css"><link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.0.13/css/all.css" ><!-- start custom head snippets --><link rel="stylesheet" href="/assets/css/expand.css">
|
|||
|
<!-- end custom head snippets --><script>(function() {
|
|||
|
window.isArray = function(val) {
|
|||
|
return Object.prototype.toString.call(val) === '[object Array]';
|
|||
|
};
|
|||
|
window.isString = function(val) {
|
|||
|
return typeof val === 'string';
|
|||
|
};
|
|||
|
|
|||
|
window.hasEvent = function(event) {
|
|||
|
return 'on'.concat(event) in window.document;
|
|||
|
};
|
|||
|
|
|||
|
window.isOverallScroller = function(node) {
|
|||
|
return node === document.documentElement || node === document.body || node === window;
|
|||
|
};
|
|||
|
|
|||
|
window.isFormElement = function(node) {
|
|||
|
var tagName = node.tagName;
|
|||
|
return tagName === 'INPUT' || tagName === 'SELECT' || tagName === 'TEXTAREA';
|
|||
|
};
|
|||
|
|
|||
|
window.pageLoad = (function () {
|
|||
|
var loaded = false, cbs = [];
|
|||
|
window.addEventListener('load', function () {
|
|||
|
var i;
|
|||
|
loaded = true;
|
|||
|
if (cbs.length > 0) {
|
|||
|
for (i = 0; i < cbs.length; i++) {
|
|||
|
cbs[i]();
|
|||
|
}
|
|||
|
}
|
|||
|
});
|
|||
|
return {
|
|||
|
then: function(cb) {
|
|||
|
cb && (loaded ? cb() : (cbs.push(cb)));
|
|||
|
}
|
|||
|
};
|
|||
|
})();
|
|||
|
})();
|
|||
|
(function() {
|
|||
|
window.throttle = function(func, wait) {
|
|||
|
var args, result, thisArg, timeoutId, lastCalled = 0;
|
|||
|
|
|||
|
function trailingCall() {
|
|||
|
lastCalled = new Date;
|
|||
|
timeoutId = null;
|
|||
|
result = func.apply(thisArg, args);
|
|||
|
}
|
|||
|
return function() {
|
|||
|
var now = new Date,
|
|||
|
remaining = wait - (now - lastCalled);
|
|||
|
|
|||
|
args = arguments;
|
|||
|
thisArg = this;
|
|||
|
|
|||
|
if (remaining <= 0) {
|
|||
|
clearTimeout(timeoutId);
|
|||
|
timeoutId = null;
|
|||
|
lastCalled = now;
|
|||
|
result = func.apply(thisArg, args);
|
|||
|
} else if (!timeoutId) {
|
|||
|
timeoutId = setTimeout(trailingCall, remaining);
|
|||
|
}
|
|||
|
return result;
|
|||
|
};
|
|||
|
};
|
|||
|
})();
|
|||
|
(function() {
|
|||
|
var Set = (function() {
|
|||
|
var add = function(item) {
|
|||
|
var i, data = this._data;
|
|||
|
for (i = 0; i < data.length; i++) {
|
|||
|
if (data[i] === item) {
|
|||
|
return;
|
|||
|
}
|
|||
|
}
|
|||
|
this.size ++;
|
|||
|
data.push(item);
|
|||
|
return data;
|
|||
|
};
|
|||
|
|
|||
|
var Set = function(data) {
|
|||
|
this.size = 0;
|
|||
|
this._data = [];
|
|||
|
var i;
|
|||
|
if (data.length > 0) {
|
|||
|
for (i = 0; i < data.length; i++) {
|
|||
|
add.call(this, data[i]);
|
|||
|
}
|
|||
|
}
|
|||
|
};
|
|||
|
Set.prototype.add = add;
|
|||
|
Set.prototype.get = function(index) { return this._data[index]; };
|
|||
|
Set.prototype.has = function(item) {
|
|||
|
var i, data = this._data;
|
|||
|
for (i = 0; i < data.length; i++) {
|
|||
|
if (this.get(i) === item) {
|
|||
|
return true;
|
|||
|
}
|
|||
|
}
|
|||
|
return false;
|
|||
|
};
|
|||
|
Set.prototype.is = function(map) {
|
|||
|
if (map._data.length !== this._data.length) { return false; }
|
|||
|
var i, j, flag, tData = this._data, mData = map._data;
|
|||
|
for (i = 0; i < tData.length; i++) {
|
|||
|
for (flag = false, j = 0; j < mData.length; j++) {
|
|||
|
if (tData[i] === mData[j]) {
|
|||
|
flag = true;
|
|||
|
break;
|
|||
|
}
|
|||
|
}
|
|||
|
if (!flag) { return false; }
|
|||
|
}
|
|||
|
return true;
|
|||
|
};
|
|||
|
Set.prototype.values = function() {
|
|||
|
return this._data;
|
|||
|
};
|
|||
|
return Set;
|
|||
|
})();
|
|||
|
|
|||
|
window.Lazyload = (function(doc) {
|
|||
|
var queue = {js: [], css: []}, sources = {js: {}, css: {}}, context = this;
|
|||
|
var createNode = function(name, attrs) {
|
|||
|
var node = doc.createElement(name), attr;
|
|||
|
for (attr in attrs) {
|
|||
|
if (attrs.hasOwnProperty(attr)) {
|
|||
|
node.setAttribute(attr, attrs[attr]);
|
|||
|
}
|
|||
|
}
|
|||
|
return node;
|
|||
|
};
|
|||
|
var end = function(type, url) {
|
|||
|
var s, q, qi, cbs, i, j, cur, val, flag;
|
|||
|
if (type === 'js' || type ==='css') {
|
|||
|
s = sources[type], q = queue[type];
|
|||
|
s[url] = true;
|
|||
|
for (i = 0; i < q.length; i++) {
|
|||
|
cur = q[i];
|
|||
|
if (cur.urls.has(url)) {
|
|||
|
qi = cur, val = qi.urls.values();
|
|||
|
qi && (cbs = qi.callbacks);
|
|||
|
for (flag = true, j = 0; j < val.length; j++) {
|
|||
|
cur = val[j];
|
|||
|
if (!s[cur]) {
|
|||
|
flag = false;
|
|||
|
}
|
|||
|
}
|
|||
|
if (flag && cbs && cbs.length > 0) {
|
|||
|
for (j = 0; j < cbs.length; j++) {
|
|||
|
cbs[j].call(context);
|
|||
|
}
|
|||
|
qi.load = true;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
};
|
|||
|
var load = function(type, urls, callback) {
|
|||
|
var s, q, qi, node, i, cur,
|
|||
|
_urls = typeof urls === 'string' ? new Set([urls]) : new Set(urls), val, url;
|
|||
|
if (type === 'js' || type ==='css') {
|
|||
|
s = sources[type], q = queue[type];
|
|||
|
for (i = 0; i < q.length; i++) {
|
|||
|
cur = q[i];
|
|||
|
if (_urls.is(cur.urls)) {
|
|||
|
qi = cur;
|
|||
|
break;
|
|||
|
}
|
|||
|
}
|
|||
|
val = _urls.values();
|
|||
|
if (qi) {
|
|||
|
callback && (qi.load || qi.callbacks.push(callback));
|
|||
|
callback && (qi.load && callback());
|
|||
|
} else {
|
|||
|
q.push({
|
|||
|
urls: _urls,
|
|||
|
callbacks: callback ? [callback] : [],
|
|||
|
load: false
|
|||
|
});
|
|||
|
for (i = 0; i < val.length; i++) {
|
|||
|
node = null, url = val[i];
|
|||
|
if (s[url] === undefined) {
|
|||
|
(type === 'js' ) && (node = createNode('script', { src: url }));
|
|||
|
(type === 'css') && (node = createNode('link', { rel: 'stylesheet', href: url }));
|
|||
|
if (node) {
|
|||
|
node.onload = (function(type, url) {
|
|||
|
return function() {
|
|||
|
end(type, url);
|
|||
|
};
|
|||
|
})(type, url);
|
|||
|
(doc.head || doc.body).appendChild(node);
|
|||
|
s[url] = false;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
};
|
|||
|
return {
|
|||
|
js: function(url, callback) {
|
|||
|
load('js', url, callback);
|
|||
|
},
|
|||
|
css: function(url, callback) {
|
|||
|
load('css', url, callback);
|
|||
|
}
|
|||
|
};
|
|||
|
})(this.document);
|
|||
|
})();
|
|||
|
</script><script>
|
|||
|
(function() {
|
|||
|
var TEXT_VARIABLES = {
|
|||
|
version: '2.2.6',
|
|||
|
sources: {
|
|||
|
font_awesome: 'https://use.fontawesome.com/releases/v5.0.13/css/all.css',
|
|||
|
jquery: '/assets/js/jquery.min.js',
|
|||
|
leancloud_js_sdk: '//cdn.jsdelivr.net/npm/leancloud-storage@3.13.2/dist/av-min.js',
|
|||
|
chart: 'https://cdn.bootcss.com/Chart.js/2.7.2/Chart.bundle.min.js',
|
|||
|
gitalk: {
|
|||
|
js: 'https://cdn.bootcss.com/gitalk/1.2.2/gitalk.min.js',
|
|||
|
css: 'https://cdn.bootcss.com/gitalk/1.2.2/gitalk.min.css'
|
|||
|
},
|
|||
|
valine: 'https://unpkg.com/valine/dist/Valine.min.js'
|
|||
|
},
|
|||
|
site: {
|
|||
|
toc: {
|
|||
|
selectors: 'h1,h2,h3'
|
|||
|
}
|
|||
|
},
|
|||
|
paths: {
|
|||
|
search_js: '/assets/search.js'
|
|||
|
}
|
|||
|
};
|
|||
|
window.TEXT_VARIABLES = TEXT_VARIABLES;
|
|||
|
})();
|
|||
|
</script>
|
|||
|
</head>
|
|||
|
<body>
|
|||
|
<div class="root" data-is-touch="false">
|
|||
|
<div class="layout--page js-page-root"><!----><div class="page__main js-page-main page__viewport hide-footer has-aside has-aside cell cell--auto">
|
|||
|
|
|||
|
<div class="page__main-inner"><div class="page__header d-print-none"><header class="header"><div class="main">
|
|||
|
<div class="header__title">
|
|||
|
<div class="header__brand"><svg id="svg" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="400" height="478.9473684210526" viewBox="0, 0, 400,478.9473684210526"><g id="svgg"><path id="path0" d="M308.400 56.805 C 306.970 56.966,303.280 57.385,300.200 57.738 C 290.906 58.803,278.299 59.676,269.200 59.887 L 260.600 60.085 259.400 61.171 C 258.010 62.428,256.198 63.600,255.645 63.600 C 255.070 63.600,252.887 65.897,252.598 66.806 C 252.460 67.243,252.206 67.600,252.034 67.600 C 251.397 67.600,247.206 71.509,247.202 72.107 C 247.201 72.275,246.390 73.190,245.400 74.138 C 243.961 75.517,243.598 76.137,243.592 77.231 C 243.579 79.293,241.785 83.966,240.470 85.364 C 239.176 86.740,238.522 88.365,237.991 91.521 C 237.631 93.665,236.114 97.200,235.554 97.200 C 234.938 97.200,232.737 102.354,232.450 104.472 C 232.158 106.625,230.879 109.226,229.535 110.400 C 228.933 110.926,228.171 113.162,226.434 119.500 C 226.178 120.435,225.795 121.200,225.584 121.200 C 225.373 121.200,225.200 121.476,225.200 121.813 C 225.200 122.149,224.885 122.541,224.500 122.683 C 223.606 123.013,223.214 123.593,223.204 124.600 C 223.183 126.555,220.763 132.911,219.410 134.562 C 218.443 135.742,217.876 136.956,217.599 138.440 C 217.041 141.424,215.177 146.434,214.532 146.681 C 214.240 146.794,214.000 147.055,214.000 147.261 C 214.000 147.467,213.550 148.086,213.000 148.636 C 212.450 149.186,212.000 149.893,212.000 150.208 C 212.000 151.386,208.441 154.450,207.597 153.998 C 206.319 153.315,204.913 150.379,204.633 147.811 C 204.365 145.357,202.848 142.147,201.759 141.729 C 200.967 141.425,199.200 137.451,199.200 135.974 C 199.200 134.629,198.435 133.224,196.660 131.311 C 195.363 129.913,194.572 128.123,193.870 125.000 C 193.623 123.900,193.236 122.793,193.010 122.540 C 190.863 120.133,190.147 118.880,188.978 115.481 C 188.100 112.928,187.151 111.003,186.254 109.955 C 185.358 108.908,184.518 107.204,183.847 105.073 C 183.280 103.273,182.497 101.329,182.108 100.753 C 181.719 100.177,180.904 98.997,180.298 98.131 C 179.693 97.265,178.939 95.576,178.624 94.378 C 178.041 92.159,177.125 90.326,175.023 87.168 C 174.375 86.196,173.619 84.539,173.342 83.486 C 172.800 81.429,171.529 79.567,170.131 78.785 C 169.654 78.517,168.697 77.511,168.006 76.549 C 167.316 75.587,166.594 74.800,166.402 74.800 C 166.210 74.800,164.869 73.633,163.421 72.206 C 160.103 68.936,161.107 69.109,146.550 69.301 C 133.437 69.474,128.581 70.162,126.618 72.124 C 126.248 72.495,125.462 72.904,124.872 73.033 C 124.282 73.163,123.088 73.536,122.219 73.863 C 121.349 74.191,119.028 74.638,117.061 74.858 C 113.514 75.254,109.970 76.350,108.782 77.419 C 107.652 78.436,100.146 80.400,97.388 80.400 C 95.775 80.400,93.167 81.360,91.200 82.679 C 90.430 83.195,89.113 83.804,88.274 84.031 C 85.875 84.681,78.799 90.910,74.400 96.243 L 73.400 97.456 73.455 106.028 C 73.526 117.055,74.527 121.238,77.820 124.263 C 78.919 125.273,80.400 127.902,80.400 128.842 C 80.400 129.202,81.075 130.256,81.900 131.186 C 83.563 133.059,85.497 136.346,86.039 138.216 C 86.233 138.886,87.203 140.207,88.196 141.153 C 89.188 142.098,90.000 143.104,90.000 143.388 C 90.000 144.337,92.129 148.594,92.869 149.123 C 93.271 149.410,93.600 149.831,93.600 150.059 C 93.600 150.286,93.932 150.771,94.337 151.136 C 94.743 151.501,95.598 153.004,96.237 154.475 C 96.877 155.947,97.760 157.351,98.200 157.596 C 98.640 157.841,99.900 159.943,101.000 162.267 C 102.207 164.817,103.327 166.644,103.825 166.876 C 104.278 167.087,105.065 168.101,105.573 169.130 C 107.658 173.348,108.097 174.093,110.006 176.647 C 111.103 178.114,112.000 179.725,112.000 180.227 C 112.000 181.048,113.425 183.163,114.678 184.200 C 115.295 184.711,117.396 188.733,117.720 190.022 C 117.855 190.562,118.603 191.633,119.381 192.402 C 120.160 193.171,121.496 195.258,122.351 197.039 C 123.206 198.820,124.167 200.378,124.487 200.501 C 124.807 200.624,125.953 202.496,127.034 204.662 C 128.114 206.828,129.676 209.299,130.505 210.153 C 131.333 211.007,132.124 212.177,132.262 212.753 C 132.618 214.239,134.291 217.048,136.288 219.5
|
|||
|
" href="/">YannStatic</a></div><!--<button class="button button--secondary button--circle search-button js-search-toggle"><i class="fas fa-search"></i></button>--><!-- <li><button class="button button--secondary button--circle search-button js-search-toggle"><i class="fas fa-search"></i></button></li> -->
|
|||
|
<!-- Champ de recherche -->
|
|||
|
<div id="searchbox" class="search search--dark" style="visibility: visible">
|
|||
|
<div class="main">
|
|||
|
<div class="search__header"></div>
|
|||
|
<div class="search-bar">
|
|||
|
<div class="search-box js-search-box">
|
|||
|
<div class="search-box__icon-search"><i class="fas fa-search"></i></div>
|
|||
|
<input id="search-input" type="text" />
|
|||
|
<!-- <div class="search-box__icon-clear js-icon-clear">
|
|||
|
<a><i class="fas fa-times"></i></a>
|
|||
|
</div> -->
|
|||
|
</div>
|
|||
|
</div>
|
|||
|
|
|||
|
</div>
|
|||
|
</div>
|
|||
|
<!-- Script pointing to search-script.js -->
|
|||
|
<script>/*!
|
|||
|
* Simple-Jekyll-Search
|
|||
|
* Copyright 2015-2020, Christian Fei
|
|||
|
* Licensed under the MIT License.
|
|||
|
*/
|
|||
|
|
|||
|
(function(){
|
|||
|
'use strict'
|
|||
|
|
|||
|
var _$Templater_7 = {
|
|||
|
compile: compile,
|
|||
|
setOptions: setOptions
|
|||
|
}
|
|||
|
|
|||
|
const options = {}
|
|||
|
options.pattern = /\{(.*?)\}/g
|
|||
|
options.template = ''
|
|||
|
options.middleware = function () {}
|
|||
|
|
|||
|
function setOptions (_options) {
|
|||
|
options.pattern = _options.pattern || options.pattern
|
|||
|
options.template = _options.template || options.template
|
|||
|
if (typeof _options.middleware === 'function') {
|
|||
|
options.middleware = _options.middleware
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
function compile (data) {
|
|||
|
return options.template.replace(options.pattern, function (match, prop) {
|
|||
|
const value = options.middleware(prop, data[prop], options.template)
|
|||
|
if (typeof value !== 'undefined') {
|
|||
|
return value
|
|||
|
}
|
|||
|
return data[prop] || match
|
|||
|
})
|
|||
|
}
|
|||
|
|
|||
|
'use strict';
|
|||
|
|
|||
|
function fuzzysearch (needle, haystack) {
|
|||
|
var tlen = haystack.length;
|
|||
|
var qlen = needle.length;
|
|||
|
if (qlen > tlen) {
|
|||
|
return false;
|
|||
|
}
|
|||
|
if (qlen === tlen) {
|
|||
|
return needle === haystack;
|
|||
|
}
|
|||
|
outer: for (var i = 0, j = 0; i < qlen; i++) {
|
|||
|
var nch = needle.charCodeAt(i);
|
|||
|
while (j < tlen) {
|
|||
|
if (haystack.charCodeAt(j++) === nch) {
|
|||
|
continue outer;
|
|||
|
}
|
|||
|
}
|
|||
|
return false;
|
|||
|
}
|
|||
|
return true;
|
|||
|
}
|
|||
|
|
|||
|
var _$fuzzysearch_1 = fuzzysearch;
|
|||
|
|
|||
|
'use strict'
|
|||
|
|
|||
|
/* removed: const _$fuzzysearch_1 = require('fuzzysearch') */;
|
|||
|
|
|||
|
var _$FuzzySearchStrategy_5 = new FuzzySearchStrategy()
|
|||
|
|
|||
|
function FuzzySearchStrategy () {
|
|||
|
this.matches = function (string, crit) {
|
|||
|
return _$fuzzysearch_1(crit.toLowerCase(), string.toLowerCase())
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
'use strict'
|
|||
|
|
|||
|
var _$LiteralSearchStrategy_6 = new LiteralSearchStrategy()
|
|||
|
|
|||
|
function LiteralSearchStrategy () {
|
|||
|
this.matches = function (str, crit) {
|
|||
|
if (!str) return false
|
|||
|
|
|||
|
str = str.trim().toLowerCase()
|
|||
|
crit = crit.trim().toLowerCase()
|
|||
|
|
|||
|
return crit.split(' ').filter(function (word) {
|
|||
|
return str.indexOf(word) >= 0
|
|||
|
}).length === crit.split(' ').length
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
'use strict'
|
|||
|
|
|||
|
var _$Repository_4 = {
|
|||
|
put: put,
|
|||
|
clear: clear,
|
|||
|
search: search,
|
|||
|
setOptions: __setOptions_4
|
|||
|
}
|
|||
|
|
|||
|
/* removed: const _$FuzzySearchStrategy_5 = require('./SearchStrategies/FuzzySearchStrategy') */;
|
|||
|
/* removed: const _$LiteralSearchStrategy_6 = require('./SearchStrategies/LiteralSearchStrategy') */;
|
|||
|
|
|||
|
function NoSort () {
|
|||
|
return 0
|
|||
|
}
|
|||
|
|
|||
|
const data = []
|
|||
|
let opt = {}
|
|||
|
|
|||
|
opt.fuzzy = false
|
|||
|
opt.limit = 10
|
|||
|
opt.searchStrategy = opt.fuzzy ? _$FuzzySearchStrategy_5 : _$LiteralSearchStrategy_6
|
|||
|
opt.sort = NoSort
|
|||
|
opt.exclude = []
|
|||
|
|
|||
|
function put (data) {
|
|||
|
if (isObject(data)) {
|
|||
|
return addObject(data)
|
|||
|
}
|
|||
|
if (isArray(data)) {
|
|||
|
return addArray(data)
|
|||
|
}
|
|||
|
return undefined
|
|||
|
}
|
|||
|
function clear () {
|
|||
|
data.length = 0
|
|||
|
return data
|
|||
|
}
|
|||
|
|
|||
|
function isObject (obj) {
|
|||
|
return Boolean(obj) && Object.prototype.toString.call(obj) === '[object Object]'
|
|||
|
}
|
|||
|
|
|||
|
function isArray (obj) {
|
|||
|
return Boolean(obj) && Object.prototype.toString.call(obj) === '[object Array]'
|
|||
|
}
|
|||
|
|
|||
|
function addObject (_data) {
|
|||
|
data.push(_data)
|
|||
|
return data
|
|||
|
}
|
|||
|
|
|||
|
function addArray (_data) {
|
|||
|
const added = []
|
|||
|
clear()
|
|||
|
for (let i = 0, len = _data.length; i < len; i++) {
|
|||
|
if (isObject(_data[i])) {
|
|||
|
added.push(addObject(_data[i]))
|
|||
|
}
|
|||
|
}
|
|||
|
return added
|
|||
|
}
|
|||
|
|
|||
|
function search (crit) {
|
|||
|
if (!crit) {
|
|||
|
return []
|
|||
|
}
|
|||
|
return findMatches(data, crit, opt.searchStrategy, opt).sort(opt.sort)
|
|||
|
}
|
|||
|
|
|||
|
function __setOptions_4 (_opt) {
|
|||
|
opt = _opt || {}
|
|||
|
|
|||
|
opt.fuzzy = _opt.fuzzy || false
|
|||
|
opt.limit = _opt.limit || 10
|
|||
|
opt.searchStrategy = _opt.fuzzy ? _$FuzzySearchStrategy_5 : _$LiteralSearchStrategy_6
|
|||
|
opt.sort = _opt.sort || NoSort
|
|||
|
opt.exclude = _opt.exclude || []
|
|||
|
}
|
|||
|
|
|||
|
function findMatches (data, crit, strategy, opt) {
|
|||
|
const matches = []
|
|||
|
for (let i = 0; i < data.length && matches.length < opt.limit; i++) {
|
|||
|
const match = findMatchesInObject(data[i], crit, strategy, opt)
|
|||
|
if (match) {
|
|||
|
matches.push(match)
|
|||
|
}
|
|||
|
}
|
|||
|
return matches
|
|||
|
}
|
|||
|
|
|||
|
function findMatchesInObject (obj, crit, strategy, opt) {
|
|||
|
for (const key in obj) {
|
|||
|
if (!isExcluded(obj[key], opt.exclude) && strategy.matches(obj[key], crit)) {
|
|||
|
return obj
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
function isExcluded (term, excludedTerms) {
|
|||
|
for (let i = 0, len = excludedTerms.length; i < len; i++) {
|
|||
|
const excludedTerm = excludedTerms[i]
|
|||
|
if (new RegExp(excludedTerm).test(term)) {
|
|||
|
return true
|
|||
|
}
|
|||
|
}
|
|||
|
return false
|
|||
|
}
|
|||
|
|
|||
|
/* globals ActiveXObject:false */
|
|||
|
|
|||
|
'use strict'
|
|||
|
|
|||
|
var _$JSONLoader_2 = {
|
|||
|
load: load
|
|||
|
}
|
|||
|
|
|||
|
function load (location, callback) {
|
|||
|
const xhr = getXHR()
|
|||
|
xhr.open('GET', location, true)
|
|||
|
xhr.onreadystatechange = createStateChangeListener(xhr, callback)
|
|||
|
xhr.send()
|
|||
|
}
|
|||
|
|
|||
|
function createStateChangeListener (xhr, callback) {
|
|||
|
return function () {
|
|||
|
if (xhr.readyState === 4 && xhr.status === 200) {
|
|||
|
try {
|
|||
|
callback(null, JSON.parse(xhr.responseText))
|
|||
|
} catch (err) {
|
|||
|
callback(err, null)
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
function getXHR () {
|
|||
|
return window.XMLHttpRequest ? new window.XMLHttpRequest() : new ActiveXObject('Microsoft.XMLHTTP')
|
|||
|
}
|
|||
|
|
|||
|
'use strict'
|
|||
|
|
|||
|
var _$OptionsValidator_3 = function OptionsValidator (params) {
|
|||
|
if (!validateParams(params)) {
|
|||
|
throw new Error('-- OptionsValidator: required options missing')
|
|||
|
}
|
|||
|
|
|||
|
if (!(this instanceof OptionsValidator)) {
|
|||
|
return new OptionsValidator(params)
|
|||
|
}
|
|||
|
|
|||
|
const requiredOptions = params.required
|
|||
|
|
|||
|
this.getRequiredOptions = function () {
|
|||
|
return requiredOptions
|
|||
|
}
|
|||
|
|
|||
|
this.validate = function (parameters) {
|
|||
|
const errors = []
|
|||
|
requiredOptions.forEach(function (requiredOptionName) {
|
|||
|
if (typeof parameters[requiredOptionName] === 'undefined') {
|
|||
|
errors.push(requiredOptionName)
|
|||
|
}
|
|||
|
})
|
|||
|
return errors
|
|||
|
}
|
|||
|
|
|||
|
function validateParams (params) {
|
|||
|
if (!params) {
|
|||
|
return false
|
|||
|
}
|
|||
|
return typeof params.required !== 'undefined' && params.required instanceof Array
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
'use strict'
|
|||
|
|
|||
|
var _$utils_9 = {
|
|||
|
merge: merge,
|
|||
|
isJSON: isJSON
|
|||
|
}
|
|||
|
|
|||
|
function merge (defaultParams, mergeParams) {
|
|||
|
const mergedOptions = {}
|
|||
|
for (const option in defaultParams) {
|
|||
|
mergedOptions[option] = defaultParams[option]
|
|||
|
if (typeof mergeParams[option] !== 'undefined') {
|
|||
|
mergedOptions[option] = mergeParams[option]
|
|||
|
}
|
|||
|
}
|
|||
|
return mergedOptions
|
|||
|
}
|
|||
|
|
|||
|
function isJSON (json) {
|
|||
|
try {
|
|||
|
if (json instanceof Object && JSON.parse(JSON.stringify(json))) {
|
|||
|
return true
|
|||
|
}
|
|||
|
return false
|
|||
|
} catch (err) {
|
|||
|
return false
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
var _$src_8 = {};
|
|||
|
(function (window) {
|
|||
|
'use strict'
|
|||
|
|
|||
|
let options = {
|
|||
|
searchInput: null,
|
|||
|
resultsContainer: null,
|
|||
|
json: [],
|
|||
|
success: Function.prototype,
|
|||
|
searchResultTemplate: '<li><a href="{url}" title="{desc}">{title}</a></li>',
|
|||
|
templateMiddleware: Function.prototype,
|
|||
|
sortMiddleware: function () {
|
|||
|
return 0
|
|||
|
},
|
|||
|
noResultsText: 'No results found',
|
|||
|
limit: 10,
|
|||
|
fuzzy: false,
|
|||
|
debounceTime: null,
|
|||
|
exclude: []
|
|||
|
}
|
|||
|
|
|||
|
let debounceTimerHandle
|
|||
|
const debounce = function (func, delayMillis) {
|
|||
|
if (delayMillis) {
|
|||
|
clearTimeout(debounceTimerHandle)
|
|||
|
debounceTimerHandle = setTimeout(func, delayMillis)
|
|||
|
} else {
|
|||
|
func.call()
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
const requiredOptions = ['searchInput', 'resultsContainer', 'json']
|
|||
|
|
|||
|
/* removed: const _$Templater_7 = require('./Templater') */;
|
|||
|
/* removed: const _$Repository_4 = require('./Repository') */;
|
|||
|
/* removed: const _$JSONLoader_2 = require('./JSONLoader') */;
|
|||
|
const optionsValidator = _$OptionsValidator_3({
|
|||
|
required: requiredOptions
|
|||
|
})
|
|||
|
/* removed: const _$utils_9 = require('./utils') */;
|
|||
|
|
|||
|
window.SimpleJekyllSearch = function (_options) {
|
|||
|
const errors = optionsValidator.validate(_options)
|
|||
|
if (errors.length > 0) {
|
|||
|
throwError('You must specify the following required options: ' + requiredOptions)
|
|||
|
}
|
|||
|
|
|||
|
options = _$utils_9.merge(options, _options)
|
|||
|
|
|||
|
_$Templater_7.setOptions({
|
|||
|
template: options.searchResultTemplate,
|
|||
|
middleware: options.templateMiddleware
|
|||
|
})
|
|||
|
|
|||
|
_$Repository_4.setOptions({
|
|||
|
fuzzy: options.fuzzy,
|
|||
|
limit: options.limit,
|
|||
|
sort: options.sortMiddleware,
|
|||
|
exclude: options.exclude
|
|||
|
})
|
|||
|
|
|||
|
if (_$utils_9.isJSON(options.json)) {
|
|||
|
initWithJSON(options.json)
|
|||
|
} else {
|
|||
|
initWithURL(options.json)
|
|||
|
}
|
|||
|
|
|||
|
const rv = {
|
|||
|
search: search
|
|||
|
}
|
|||
|
|
|||
|
typeof options.success === 'function' && options.success.call(rv)
|
|||
|
return rv
|
|||
|
}
|
|||
|
|
|||
|
function initWithJSON (json) {
|
|||
|
_$Repository_4.put(json)
|
|||
|
registerInput()
|
|||
|
}
|
|||
|
|
|||
|
function initWithURL (url) {
|
|||
|
_$JSONLoader_2.load(url, function (err, json) {
|
|||
|
if (err) {
|
|||
|
throwError('failed to get JSON (' + url + ')')
|
|||
|
}
|
|||
|
initWithJSON(json)
|
|||
|
})
|
|||
|
}
|
|||
|
|
|||
|
function emptyResultsContainer () {
|
|||
|
options.resultsContainer.innerHTML = ''
|
|||
|
}
|
|||
|
|
|||
|
function appendToResultsContainer (text) {
|
|||
|
options.resultsContainer.innerHTML += text
|
|||
|
}
|
|||
|
|
|||
|
function registerInput () {
|
|||
|
options.searchInput.addEventListener('input', function (e) {
|
|||
|
if (isWhitelistedKey(e.which)) {
|
|||
|
emptyResultsContainer()
|
|||
|
debounce(function () { search(e.target.value) }, options.debounceTime)
|
|||
|
}
|
|||
|
})
|
|||
|
}
|
|||
|
|
|||
|
function search (query) {
|
|||
|
if (isValidQuery(query)) {
|
|||
|
emptyResultsContainer()
|
|||
|
render(_$Repository_4.search(query), query)
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
function render (results, query) {
|
|||
|
const len = results.length
|
|||
|
if (len === 0) {
|
|||
|
return appendToResultsContainer(options.noResultsText)
|
|||
|
}
|
|||
|
for (let i = 0; i < len; i++) {
|
|||
|
results[i].query = query
|
|||
|
appendToResultsContainer(_$Templater_7.compile(results[i]))
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
function isValidQuery (query) {
|
|||
|
return query && query.length > 0
|
|||
|
}
|
|||
|
|
|||
|
function isWhitelistedKey (key) {
|
|||
|
return [13, 16, 20, 37, 38, 39, 40, 91].indexOf(key) === -1
|
|||
|
}
|
|||
|
|
|||
|
function throwError (message) {
|
|||
|
throw new Error('SimpleJekyllSearch --- ' + message)
|
|||
|
}
|
|||
|
})(window)
|
|||
|
|
|||
|
}());
|
|||
|
</script>
|
|||
|
|
|||
|
<!-- Configuration -->
|
|||
|
<script>
|
|||
|
SimpleJekyllSearch({
|
|||
|
searchInput: document.getElementById('search-input'),
|
|||
|
resultsContainer: document.getElementById('results-container'),
|
|||
|
json: '/search.json',
|
|||
|
//searchResultTemplate: '<li><a href="https://static.rnmkcy.eu{url}">{date} {title}</a></li>'
|
|||
|
searchResultTemplate: '<li><a href="{url}">{date} {title}</a></li>'
|
|||
|
})
|
|||
|
</script>
|
|||
|
<!-- Fin déclaration champ de recherche --></div><nav class="navigation">
|
|||
|
<ul><li class="navigation__item"><a href="/archive.html">Etiquettes</a></li><li class="navigation__item"><a href="/htmldoc.html">Documents</a></li><li class="navigation__item"><a href="/liens_ttrss.html">Liens</a></li><li class="navigation__item"><a href="/aide-jekyll-text-theme.html">Aide</a></li></ul>
|
|||
|
</nav></div>
|
|||
|
</header>
|
|||
|
|
|||
|
</div><div class="page__content"><div class ="main"><div class="grid grid--reverse">
|
|||
|
<div class="col-main cell cell--auto"><!-- start custom main top snippet --><div id="results-container" class="search-result js-search-result"></div><!-- end custom main top snippet -->
|
|||
|
<article itemscope itemtype="http://schema.org/Article"><div class="article__header"><header><h1 style="color:Tomato;">utiliser-son-android-de-facon-plus-securisee</h1></header></div><meta itemprop="headline" content="utiliser-son-android-de-facon-plus-securisee"><div class="article__info clearfix"><ul class="left-col menu"><li>
|
|||
|
<a class="button button--secondary button--pill button--sm"
|
|||
|
href="/archive.html?tag=android">android</a>
|
|||
|
</li></ul><ul class="right-col menu"><li>
|
|||
|
<i class="far fa-calendar-alt"></i> <span title="Création" style="color:#FF00FF">25 déc. 2019</span>
|
|||
|
|
|||
|
<span title="Modification" style="color:#00FF7F">23 nov. 2018</span></li></ul></div><meta itemprop="datePublished" content="2018-11-23T00:00:00+01:00">
|
|||
|
<meta itemprop="keywords" content="android"><div class="js-article-content">
|
|||
|
<div class="layout--article"><!-- start custom article top snippet -->
|
|||
|
<style>
|
|||
|
#myBtn {
|
|||
|
display: none;
|
|||
|
position: fixed;
|
|||
|
bottom: 10px;
|
|||
|
right: 10px;
|
|||
|
z-index: 99;
|
|||
|
font-size: 12px;
|
|||
|
font-weight: bold;
|
|||
|
border: none;
|
|||
|
outline: none;
|
|||
|
background-color: white;
|
|||
|
color: black;
|
|||
|
cursor: pointer;
|
|||
|
padding: 5px;
|
|||
|
border-radius: 4px;
|
|||
|
}
|
|||
|
|
|||
|
#myBtn:hover {
|
|||
|
background-color: #555;
|
|||
|
}
|
|||
|
</style>
|
|||
|
|
|||
|
<button onclick="topFunction()" id="myBtn" title="Haut de page">⇧</button>
|
|||
|
|
|||
|
<script>
|
|||
|
//Get the button
|
|||
|
var mybutton = document.getElementById("myBtn");
|
|||
|
|
|||
|
// When the user scrolls down 20px from the top of the document, show the button
|
|||
|
window.onscroll = function() {scrollFunction()};
|
|||
|
|
|||
|
function scrollFunction() {
|
|||
|
if (document.body.scrollTop > 20 || document.documentElement.scrollTop > 20) {
|
|||
|
mybutton.style.display = "block";
|
|||
|
} else {
|
|||
|
mybutton.style.display = "none";
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
// When the user clicks on the button, scroll to the top of the document
|
|||
|
function topFunction() {
|
|||
|
document.body.scrollTop = 0;
|
|||
|
document.documentElement.scrollTop = 0;
|
|||
|
}
|
|||
|
</script>
|
|||
|
|
|||
|
|
|||
|
<!-- end custom article top snippet -->
|
|||
|
<div class="article__content" itemprop="articleBody"><details>
|
|||
|
<summary><b>Afficher/cacher Sommaire</b></summary>
|
|||
|
<!-- affichage sommaire -->
|
|||
|
<div class="toc-aside js-toc-root"></div>
|
|||
|
</details><p>URL: https://linuxfr.org/news/utiliser-son-android-de-facon-plus-securisee
|
|||
|
Title: Utiliser son Android de façon plus sécurisée
|
|||
|
Authors: voxdemonix
|
|||
|
ZeroHeure, BAud, Davy Defaud, Yves Bourguignon, jcr83, Nils Ratusznik, palm123, xev et Pierre Jarillon
|
|||
|
Date: 2018-06-03T19:16:13+02:00
|
|||
|
License: CC by-sa
|
|||
|
Tags: android, sécurité, cybersécurité et smartphone
|
|||
|
Score: 21</p>
|
|||
|
|
|||
|
<p>Android, le système d’exploitation largement majoritaire sur les mobiles, est, comme chacun le sait sur <em>LinuxFr.org</em>, construit sur un noyau Linux.</p>
|
|||
|
|
|||
|
<p>Linux étant sous licence GPL, tout peut vous sembler parfait, mais en réalité la couche applicative Android est beaucoup moins amicale que son noyau Linux.</p>
|
|||
|
|
|||
|
<p>Le but de cet article est de vous expliquer le fonctionnement d’Android, de vous faire découvrir sa face cachée et de vous expliquer comment vivre avec dans les meilleures conditions possibles.</p>
|
|||
|
|
|||
|
<hr />
|
|||
|
|
|||
|
<p><a href="https://linuxfr.org/users/partagetonsavoir/journaux/utiliser-son-android-de-facon-plus-securise">Journal à l’origine de la dépêche</a></p>
|
|||
|
|
|||
|
<hr />
|
|||
|
|
|||
|
<p>Origine de l’article : <a href="https://www.0rion.netlib.re/forum4/viewtopic.php?f=79&t=779">via Web</a> ou <a href="http://fr47f6ecynx4dgq6.onion/forum4/viewtopic.php?f=79&t=779">via Tor</a>.
|
|||
|
<img src="https://image.noelshack.com/fichiers/2018/22/7/1528024223-android.jpg" alt="En‐tête de l’article" /> 🍭 <em>Si tu fais des conneries avec ta vie privée et celle des autres, tu es une balance, peu importe tes excuses ou ton déni.</em> 🍭</p>
|
|||
|
|
|||
|
<h1 id="point-de-départ">Point de Départ</h1>
|
|||
|
<p>Introduction
|
|||
|
————
|
|||
|
<a href="https://fr.wikipedia.org/wiki/Android">Android</a> est un système en partie libre, assez dur à dompter tout en étant celui offrant le plus de possibilités. Il est généralement livré avec des applications publicitaires, des <a href="https://fr.wikipedia.org/wiki/Logiciel_espion">espiongiciels (<em>spywares/tracker</em>)</a> à la pelle (surtout <a href="https://fr.wikipedia.org/wiki/Google_Analytics">Google Analytics</a>) et autres applications dérangeantes autant pour le confort personnel, la philosophie que l’aspect sécuritaire ou énergétique.
|
|||
|
Par exemple, lors de l’initialisation de votre appareil, Facebook (qui est préinstallé sur quasi tous les appareils Android) va récupérer votre liste de contacts et se l’auto‐envoyer, même si vous n’avez jamais utilisé FB de toute votre vie.</p>
|
|||
|
|
|||
|
<p>Les opérateurs et fabricants ont tendance à modifier le système — par exemple, HTC qui insère son propre lanceur (<em>launcher</em>) et ses propres <em>widgets</em> — l’existence de différences d’un mobile Android à un autre est donc « normale ».</p>
|
|||
|
|
|||
|
<p>Petit rappel : votre machine vous sert souvent pour communiquer avec d’autres humains. <em>Grosso modo</em>, elle sert d’organe comme votre bouche et vos oreilles. Si vous et vos interlocuteurs ne pouvez faire confiance à votre bouche et vos oreilles, comment communiquer avec vous ?</p>
|
|||
|
|
|||
|
<p>Attention : méfiez‐vous des trop nombreux comparatifs dont le but n’est point de vous aider à choisir le bon logiciel mais plutôt de rapporter de l’argent à son auteur.</p>
|
|||
|
|
|||
|
<h2 id="petit-résumé-du-fonctionnement-dandroid">Petit résumé du fonctionnement d’Android</h2>
|
|||
|
<p><a href="https://fr.wikipedia.org/wiki/Android">Android</a> est un moteur <a href="https://fr.wikipedia.org/wiki/Linux">Linux</a>, faisant tourner une <a href="https://fr.wikipedia.org/wiki/Machine_virtuelle">machine virtuelle</a> (émulateur) exécutant du <a href="https://fr.wikipedia.org/wiki/Java_%28langage%29">Java</a>.
|
|||
|
Contrairement aux systèmes sur ordinateur où chaque application range ses données dans son coin et où c’est parfois le bordel, sur Android, certaines informations sont centralisées dans une <a href="https://fr.m.wikipedia.org/wiki/Base_de_donn%C3%A9es">base de données</a> principale. Ainsi, chaque application y aura accès ou non selon votre gestion des permissions. De fait, les calendriers, les SMS/MMS, la position et les contacts peuvent être accessibles à toutes les applications sans passer par la case exportation. Le danger est justement cette facilité d’accès pour les applications préinstallées par les <a href="https://fr.m.wikipedia.org/wiki/Op%C3%A9rateur_de_r%C3%A9seau_mobile">opérateurs</a>, auxquelles ces derniers auront sournoisement autorisé toutes les permissions.
|
|||
|
Android ne permet pas encore une utilisation aussi poussée que sur ordinateur. On citera, entre autres, la difficulté abusive pour programmer ou scripter, l’impossibilité d’afficher plusieurs fenêtres en même temps, l’absence du montage à distance, etc.</p>
|
|||
|
|
|||
|
<p>Un truc très important à savoir avec les appareils Android : le nombre d’applications installables ou à mettre à jour sur un appareil diminue avec le temps car les nouvelles versions ont besoin d’un système plus récent.</p>
|
|||
|
|
|||
|
<p><strong>Explications détaillées pour les barbus :</strong> En effet, il n’y a plus de mises à jours système après environ deux ans de vie du produit. La raison majeure étant que l’<a href="https://fr.wikipedia.org/wiki/Architecture_ARM">architecture ARM</a> elle‐même est très morcelée et la prise en charge varie fortement entre les différents concepteurs de briques de base (processeur, décodage vidéo, accélération 3D, Wi‐Fi, etc.), les assembleurs de <a href="https://fr.wikipedia.org/wiki/SoC">systèmes monopuces (SoC)</a> qui en plus apportent des spécificités, les assembleurs de téléphones qui en rajoutent une couche en termes de matériel et de logiciel, puis éventuellement l’opérateur chez qui le téléphone a été acheté et qui ajoute sa surcouche logicielle.
|
|||
|
Au final, n’importe quel maillon peut flancher et, en bout de chaîne, il est banal de se retrouver avec une image Android qui traîne de vieux pilotes, qui n’est pas facile à maintenir et qui, avouons‐le, arrange bien les fabricants de téléphones qui ont une nouvelle gamme à vendre et qui conçoivent leurs produits au plus juste de la garantie légale et avec des ambitions marketing (comme pouvoir afficher de grosses autonomies au détriment de la durabilité de la batterie).
|
|||
|
Google (qui possède Android) essaye, via le <a href="https://www.lesnumeriques.com/telephone-portable/project-treble-reponse-google-a-fragmentation-android-n63061.html">projet Treble</a>, de limiter en partie ce problème.</p>
|
|||
|
|
|||
|
<h2 id="règles-de-base">Règles de base</h2>
|
|||
|
<ul>
|
|||
|
<li><strong>Méfiez‐vous de ce que vous installez ou de ce qui est préinstallé :</strong> n’installez pas des applications inutiles, à la provenance douteuse (y compris sur le <em>Play Store</em>) ou demandant des permissions suspicieuses. N’oubliez pas non plus que la plupart des <a href="https://fr.wikipedia.org/wiki/Cheval_de_Troie_(informatique)">chevaux de Troie</a> se cachent dans des applications d’un premier abord normales. Votre vie privée ne peut être protégée si vous installez des applications qui pompent toutes vos données. Afin de les éviter au maximum, utilisez des <a href="https://fr.wikipedia.org/wiki/Logiciel_libre">applications libres</a> en lieu et place de celles installées par défaut (attention, certaines applications libres, provenant généralement des fabricants, embarquent <a href="https://fr.wikipedia.org/wiki/Google_Analytics">Google Analytics</a>).</li>
|
|||
|
<li><strong>Verrouillage de l’écran :</strong> toujours laisser le verrouillage automatique de l’écran. La majorité des piratages s’explique par un proche qui pique le mobile ou va sur le PC non verrouillé quand on a le dos tourné.</li>
|
|||
|
<li><strong>Un service ou une application conçue dans votre pays n’est pas de meilleure qualité « parce que voilà ».</strong> Il faut que les gens derrière l’application ou le service poursuivent des objectifs finals concordant avec vos attentes. La communauté aussi est très importante, elle ne doit pas être composée en majorité d’imbéciles demandant des <a href="http://www.planet-libre.org/index.php?post_id=16592">anti‐fonctionnalités</a> (voir, par exemple, les commentaires sous les applications foscam où des gens demandent l’introduction de ce qu’un averti appellerait une « <a href="https://fr.wikipedia.org/wiki/Backdoor">porte dérobée</a> »).
|
|||
|
Évitez quand même les pays à mauvaise réputation (Chine, Russie, Moyen Orient, Turquie).</li>
|
|||
|
<li><strong>L’antivirus ne vous protégera jamais de vos incompétences ou méconnaissances.</strong> L’antivirus ne peut vous protéger de vos propres erreurs. Si vous exécutez une application contenant un « pourriciel » (<em>malware</em>), que votre antivirus vous demande si c’est normal et que vous répondez <em>Oui</em>, alors l’antivirus ne va pas bloquer le vilain. Aucun antivirus ne vous protégera jamais de vos propres actions.</li>
|
|||
|
<li><strong>C’est normal de ne pas tout savoir.</strong> Personne n’est omniscient, vous ne savez pas tout sur tout et allez commettre des erreurs. Il faut l’accepter et réfléchir à comment diminuer l’impact de vos erreurs éventuelles.</li>
|
|||
|
<li><strong>Ne laissez pas vos émetteurs‐récepteurs allumés inutilement.</strong> N’oubliez surtout pas de couper le Wi‐Fi, le Bluetooth et le NFC lorsque vous n’en avez pas besoin. Il faut savoir qu’il est très, très, très facile de vous suivre grâce aux identifiants (voir <a href="https://fr.wikipedia.org/wiki/Adresse_mac">adresse MAC</a>) et ce, sans que vous soyez connecté. En effet, votre machine va polluer régulièrement l’air de requêtes permettant de savoir si un des réseaux (pour le Wi‐Fi) ou une des machines (pour le Bluetooth) avec « connexion automatique » (par défaut) est à portée de connexion.</li>
|
|||
|
<li><strong>Ne vous connectez à des services qu’en HTTPS, jamais en HTTP. (sauf les <code class="language-plaintext highlighter-rouge">.onion</code>)</strong> Il vous arrive probablement de vous connecter à des réseaux Wi‐Fi non sécurisés, à des réseau privés virtuels (VPN) ou à Tor. Il ne faut <strong>jamais</strong> faire confiance aux machines intermédiaires entre vous et le destinataire. Pour éviter de vous faire piller vos mots de passe, utilisez toujours HTTPS.</li>
|
|||
|
</ul>
|
|||
|
|
|||
|
<h1 id="premiers-pas">Premiers pas</h1>
|
|||
|
<p><strong>Note :</strong> prenez votre temps, en cas d’erreur le risque c’est de foutre en l’air votre machine et les réparations ne sont pas gratuites. À vos risques et périls, <em>hacker</em> vaillant rien d’impossible !</p>
|
|||
|
|
|||
|
<h2 id="avant-lachat">Avant l’achat</h2>
|
|||
|
<p>Avant d’acheter un nouvel appareil il faut vérifier sur Internet que ce n’est pas juste une bouse de marketeux. Pour ce faire, renseignez‐vous afin de connaître les retours d’expérience d’autres personnes (attention aux faux com’), de savoir s’il est facilement « rootable », si les mises à jour système ne se bloquent pas au bout de six mois, etc. Ne succombez surtout pas aux publicités sans vérifier derrière et ne soyez pas le premier de tout l’Internet à tenter de « rooter » un nouvel appareil. ;)</p>
|
|||
|
|
|||
|
<h2 id="root-accès-superutilisateur">Root (accès super‐utilisateur)</h2>
|
|||
|
<p><strong>Attention :</strong> risque de bloquer votre machine (<em>break</em>, <em>freeze</em>, <a href="https://fr.wikipedia.org/wiki/Bootloop"><em>bootloop</em></a>)</p>
|
|||
|
|
|||
|
<p><strong>Explications :</strong> L’accès <em><a href="https://fr.wikipedia.org/wiki/Utilisateur_root">root</a></em> vous permet d’autoriser des applications à accomplir des actions en <a href="https://fr.wikipedia.org/wiki/Utilisateur_root">super‐utilisateur</a>. Pour avoir accès en super‐utilisateur, sur la plupart des machines Android, il vous faudra utiliser un <em>hack</em>. Cette bidouille est parfois prévue par les fabricants (par exemple, <a href="https://fr.wikipedia.org/wiki/HTC">HTC</a> et <a href="https://fr.wikipedia.org/wiki/Sony">Sony</a> qui vous fournissent un tuto si vous leur offrez vos informations personnelles [<em>tracking</em>]). La raison pour laquelle l’accès <em>root</em> est aussi difficile à avoir est simple : vous interdire de supprimer les applications publicitaires, ainsi que les logiciels espions des fabricants, opérateurs, fournisseurs ou encore étatiques, et vous empêcher d’avoir le contrôle complet de votre machine.
|
|||
|
Attention, déverrouiller le chargeur d’amorçage (pour pouvoir « rooter ») peut provoquer la fin de la garantie pour certains appareils.</p>
|
|||
|
|
|||
|
<p><strong>Chaque appareil aura donc une méthode spécifique pour avoir accès en super‐utilisateur, mais en général, vous devrez :</strong></p>
|
|||
|
|
|||
|
<ol>
|
|||
|
<li>désactiver le chiffrement de la partition :
|
|||
|
<ul>
|
|||
|
<li>lancez votre appareil sans carte SIM,</li>
|
|||
|
<li>si c’est votre premier lancement, dites non à un maximum des questions qu’il va vous poser et faites la mise à jour système,</li>
|
|||
|
<li>une fois l’appareil lancé, allez dans <em>Paramètres</em> → <em>Verrouillage d’écran et sécurité</em> → <em>Chiffrer l’appareil</em> → <em>Désactiver le chiffrement des données</em> (vous pourrez, au choix, le réactiver plus tard ou non, si votre ROM est compatible) ;</li>
|
|||
|
</ul>
|
|||
|
</li>
|
|||
|
<li>déverrouiller le chargeur d’amorçage (<em><a href="https://www.androidpit.fr/c-est-quoi-bootloader-android">bootloader</a></em>) ;</li>
|
|||
|
<li>« rooter » votre appareil en suivant la procédure spécifique à l’appareil (cherchez sur un moteur de recherche « root <em>nom_COMPLET_de_votre_appareil</em> »).</li>
|
|||
|
</ol>
|
|||
|
|
|||
|
<h2 id="premier-lancement-dandroid">Premier lancement d’Android</h2>
|
|||
|
<ol>
|
|||
|
<li>/!\ ne placez surtout pas votre carte SIM ;</li>
|
|||
|
<li>répondez aux questions afin de lancer l’appareil ; veillez à décliner respectueusement toutes les offres de vous faire espionner et choisissez ignorer lorsque l’appareil vous demandera le code du Wi‐Fi ;</li>
|
|||
|
<li>une fois l’appareil lancé, rendez‐vous dans vos <em>Paramètres</em> puis <em>Applications</em> et <em>Forcez l’arrêt</em> puis <em>Désactivez</em> les applications chelou (Facebook et compagnie) en veillant à ne pas toucher aux applications risquant de rendre instable votre appareil — pour les applications de votre opérateur ou du fabricant il faudra se renseigner sur le Net, voire y aller à tâtons avec le risque de casser votre appareil, donc faites très attention ; si après avoir désactivé une application vous commencez à avoir plein d’erreurs provenant du système Android, réactivez cette application <strong>avant</strong> tout redémarrage du système (sinon, risque de <em><a href="https://fr.wikipedia.org/wiki/Bootloop">bootloop</a></em>) ;</li>
|
|||
|
<li>désactivez les publicités ciblées, voire tout ce qui utilise un compte Google, Microsoft, Apple, etc. ;</li>
|
|||
|
<li>désactivez la gestion du NFC (à moins que vous ne l’utilisiez) ;</li>
|
|||
|
<li>autorisez l’installation d’application en dehors du Google Play Store ;</li>
|
|||
|
<li>installez <a href="https://f-droid.org/">F-Droid</a>, la bibliothèque d’applications libres puis <a href="https://f-droid.org/packages/com.github.yeriomin.yalpstore/">YalpStore</a> pour pouvoir installer les applications provenant du Google Play Store sans passer par ce dernier.</li>
|
|||
|
</ol>
|
|||
|
|
|||
|
<h1 id="communiquer-avec-dautres-humains">Communiquer avec d’autres humains</h1>
|
|||
|
<p>Via Internet
|
|||
|
————</p>
|
|||
|
<h3 id="xmpp--tor">XMPP + Tor</h3>
|
|||
|
<p><img src="https://image.noelshack.com/fichiers/2018/22/7/1528025433-tor-xmpp-movim.gif" alt="Animation expliquant Tor + XMPP" /></p>
|
|||
|
|
|||
|
<p>Applications : <a href="https://f-droid.org/en/packages/eu.siacs.conversations/">Conversation</a> et/ou <a href="https://f-droid.org/en/packages/com.movim.movim/">Movim</a> + <a href="https://guardianproject.info/apps/orbot/">Orbot</a>
|
|||
|
<a href="https://fr.wikipedia.org/wiki/XMPP">XMPP</a> est le protocole qui se cache derrière <a href="https://movim.eu/">Movim</a> et <a href="https://conversations.im/">Conversation</a>, deux puissants clients de communication qui vous permettront d’oublier Facebook une bonne fois pour toutes.
|
|||
|
Movim est une alternative complète à Facebook, alors que Conversation est une alternative à Messenger (l’application de clavardage de Facebook).
|
|||
|
Afin d’empêcher le pistage via l’adresse IP, que vous hébergiez votre propre serveur <a href="https://fr.wikipedia.org/wiki/XMPP">XMPP</a> ou que vous soyez inscrit sur un serveur de la confédération, il est conseillé d’utiliser <a href="https://guardianproject.info/apps/orbot/">Orbot</a>. Ce dernier va, pour vos données circulant entre vous et le serveur <a href="https://fr.wikipedia.org/wiki/XMPP">XMPP</a>, les faire transiter par le réseau <a href="https://fr.wikipedia.org/wiki/Tor_%28r%C3%A9seau%29">Tor</a> et ainsi dissimuler votre adresse IP. C’est assez important si vous vous déplacez avec votre appareil afin d’empêcher la géolocalisation, plus particulièrement si vous utilisez les points d’accès Wi‐Fi gratuits (<em><a href="https://fr.wikipedia.org/wiki/Borne_Wi-Fi">hotspots</a></em>) et réseaux <a href="https://fr.wikipedia.org/wiki/FON">FON</a> (dont vos changements d’adresse IP au fur et à mesure de vos connexions aux différents points d’accès <a href="https://fr.wikipedia.org/wiki/FON">FON</a> vont permettre de récupérer vos déplacements plus facilement qu’en 4G) :</p>
|
|||
|
|
|||
|
<ol>
|
|||
|
<li>ouvrez Fdroid, activez le dépôt <em>Gardian Project</em> et cherchez puis installez Orbot et, au choix, Conversation ou Movim (ou les deux) ;</li>
|
|||
|
<li>lancez Orbot, activez le <em>mode RPV</em> puis allez dans <em>Applis pouvant utiliser Tor</em> et cochez Movim et Conversation ;</li>
|
|||
|
<li>lancez ensuite Movim ou Conversation au choix et soit rentrez les informations pour vous connecter, soit créez un nouveau compte, mais attention : si la création de compte est gratuite dans la fédération Movim, celle chez Conversation est payante (8 €/an) ;</li>
|
|||
|
<li>si vous utilisez Conversation, rendez‐vous dans les <em>Options</em> puis <em>Options avancées</em> et cochez <em>utiliser Tor</em> ;</li>
|
|||
|
<li><em>enjoy!</em></li>
|
|||
|
</ol>
|
|||
|
|
|||
|
<p><strong>Conversation</strong>
|
|||
|
<img src="https://image.noelshack.com/fichiers/2018/22/7/1528025497-screenshot-conversation.jpg" alt="Capture d’écran de l’application Android Conversation" /></p>
|
|||
|
|
|||
|
<p><strong>Movim</strong>
|
|||
|
<img src="https://image.noelshack.com/fichiers/2018/22/7/1528025564-android-movim-demo.gif" alt="Capture d’écran de l’application Android Movim" /></p>
|
|||
|
|
|||
|
<h2 id="via-sms">Via SMS</h2>
|
|||
|
<p><strong>Note :</strong> tout message envoyé non chiffré peut être lu par l’opérateur et le <a href="https://fr.wikipedia.org/wiki/Processeur_de_bande_de_base">modem de l’appareil</a>.</p>
|
|||
|
|
|||
|
<h3 id="silence-le-plus-sécurisé">Silence (le plus sécurisé)</h3>
|
|||
|
<p><img src="https://image.noelshack.com/fichiers/2018/22/7/1528025607-silence.png" alt="Logo de Silence" />
|
|||
|
<a href="https://fr.wikipedia.org/wiki/Silence_%28application%29">Silence</a> est une <a href="https://fr.wikipedia.org/wiki/Logiciel_libre">application libre</a> (licence <a href="https://github.com/SilenceIM/Silence/blob/master/LICENSE">GPL v3</a>) permettant d’envoyer et de recevoir des <a href="https://fr.wikipedia.org/wiki/Sms">SMS</a>. Sa particularité est de <a href="https://fr.wikipedia.org/wiki/Chiffrement">chiffrer</a> les SMS, ils sont donc illisibles autant pour les autres applications que pour un éventuel voleur de mobile. En revanche, elle ne résiste pas longtemps aux <a href="https://fr.wikipedia.org/wiki/Attaque_par_force_brute">attaques par force brute</a> via serveur.
|
|||
|
La sécurité qu’elle amène peut en revanche provoquer des problèmes d’intégration avec d’autres applications : l’application <em>Contact</em> ne pourra plus afficher les derniers SMS envoyés et reçus dans les informations dudit contact, <a href="https://f-droid.org/en/packages/fr.unix_experience.owncloud_sms/">Nextcloud-SMS</a> ne pourra plus récupérer les SMS, les applications de sauvegarde non plus.
|
|||
|
<a href="https://fr.wikipedia.org/wiki/Silence_%28application%29">Silence</a> peut envoyer des SMS chiffrés si l’expéditeur et le destinataire ont tous deux l’application installée. Mais le <a href="https://fr.wikipedia.org/wiki/Chiffrement">chiffrement</a> a un coût : la taille maximum d’un SMS passe de 140 caractères à une septantaine seulement.
|
|||
|
Petit défaut : les émoticônes ne sont pas toujours automatiquement transformées en images.
|
|||
|
<img src="https://image.noelshack.com/fichiers/2018/22/7/1528025658-silence-screenshot.png" alt="Capture d’écran de l’application Android Silence" /></p>
|
|||
|
|
|||
|
<h3 id="qksms-le-plus-intégré">QKSMS (le plus intégré)</h3>
|
|||
|
<p><img src="https://image.noelshack.com/fichiers/2018/22/7/1528025704-qksms-logo.png" alt="Logo QKSMS" /></p>
|
|||
|
|
|||
|
<p><a href="https://github.com/moezbhatti/qksms">QKSMS</a> est une <a href="https://fr.wikipedia.org/wiki/Logiciel_libre">application libre</a> (licence <a href="https://github.com/SilenceIM/Silence/blob/master/LICENSE">GPL v3</a>) permettant d’envoyer et de recevoir des <a href="https://fr.wikipedia.org/wiki/Sms">SMS</a>. Elle est très bien intégrée au système Android et peut fonctionner avec <a href="https://f-droid.org/en/packages/fr.unix_experience.owncloud_sms/">Nextcloud-SMS</a>, etc. Les mises à jour sont régulières, les émoticônes automatiquement transformées en image (si vous avez coché l’option dans les paramètres), les SMS ne sont pas <a href="https://fr.wikipedia.org/wiki/Chiffrement">chiffrés</a>.
|
|||
|
Selon vos préférences, vous pouvez l’installer via <a href="https://f-droid.org/en/packages/com.moez.QKSMS/">F-Droid</a> ou via <a href="https://play.google.com/store/apps/details?id=com.moez.QKSMS">Google Play Store</a>.</p>
|
|||
|
|
|||
|
<p><img src="https://image.noelshack.com/fichiers/2018/22/7/1528025746-android-qksms-demo.gif" alt="Démo Android QKSMS" /></p>
|
|||
|
|
|||
|
<h1 id="gestion-de-la-mémoire">Gestion de la mémoire</h1>
|
|||
|
<p>Le Cloud et la synchronisation des données
|
|||
|
——————————————
|
|||
|
Vos données font partie de votre mémoire et il faut en prendre soin. Ainsi, il est important de sauvegarder ses données afin de se prémunir des pannes <strong>matérielles</strong>. Avant, on utilisait des <a href="https://fr.wikipedia.org/wiki/Sauvegarde">sauvegardes</a> sur des disques durs externes qui prenaient la poussière. Et lorsque le disque dur externe tombait en panne, on perdait nos données. Aujourd’hui, il y a le <em>Cloud</em> qui permet de sous‐traiter la mémoire chez un fournisseur de stockage en ligne. Bien entendu, rien ne vous empêche d’être vous‐même votre propre fournisseur <em>Cloud</em>.
|
|||
|
Mais attention, le <em>Cloud</em> permet de se prémunir des pannes matérielles mais pas d’un piratage ou d’une extorsion de mot de passe.
|
|||
|
Pour ce faire, privilégiez donc les services de fournisseurs envers qui vous avez relativement confiance. Ces fournisseurs doivent autant que faire se peut utiliser des <a href="https://fr.wikipedia.org/wiki/Logiciel_libre">technologies libres</a> qui ont pour énorme gain, entre autres, de pousser à toujours plus de sécurité.
|
|||
|
N’hésitez pas à couper la synchronisation durant la nuit, sauf si vous avez des données à synchroniser. En effet, les logiciels de synchro consomment autant d’énergie et de données de nuit que de jour.
|
|||
|
<strong>Avec un serveur <a href="https://nextcloud.com/">Nextcloud</a> (<a href="https://www.0rion.netlib.re/forum4/viewtopic.php?f=107&t=401">tuto d’install</a>) et votre Android, vous pouvez :</strong></p>
|
|||
|
|
|||
|
<ul>
|
|||
|
<li>synchroniser vos fichiers en toute sécurité ;</li>
|
|||
|
<li><a href="https://www.0rion.netlib.re/forum4/viewtopic.php?f=93&t=748">exporter la géolocalisation avec GpsLogger</a> ;</li>
|
|||
|
<li><a href="https://linuxfr.org/wiki/tuto-howto-android-synchroniser-ses-notes-sur-nextcloud-ou-owncloud">synchroniser vos notes</a> ;</li>
|
|||
|
<li><a href="https://linuxfr.org/wiki/tuto-howto-android-synchroniser-calendrier-via-owncloud-nextcloud">synchroniser vos calendriers</a> ;</li>
|
|||
|
<li>exporter automatiquement vos photos et vidéos ;</li>
|
|||
|
<li>sauvegarder vos SMS.</li>
|
|||
|
</ul>
|
|||
|
|
|||
|
<h2 id="le-chiffrement">Le chiffrement</h2>
|
|||
|
<p>Vous pouvez chiffrer le contenu de la mémoire du mobile et ce sans installer d’application supplémentaire, c’est complètement géré par Android. Le <a href="https://fr.wikipedia.org/wiki/Chiffrement">chiffrement</a> permet de rendre illisible le contenu de la mémoire pour un voleur, tant que ce dernier ne dispose pas d’une puissance de calcul suffisante pour lancer une <a href="https://fr.wikipedia.org/wiki/Attaque_par_force_brute">attaque par force brute</a>.
|
|||
|
Sachez que le chiffrement a un impact sur les performances de la machine, qui peut varier en fonction du processeur et de la qualité de la mémoire.
|
|||
|
Attention : le chiffrement de la mémoire n’est pas toujours compatible ou stable avec les gestionnaires d’amorçage (<em>bootloaders</em>) déverrouillés, bien que les retours aient l’air positif. En revanche, toutes les <a href="https://www.xda-developers.com/what-is-custom-rom-android/">ROM</a> ne gèrent pas forcément le chiffrement.</p>
|
|||
|
|
|||
|
<h1 id="gestion-des-applications">Gestion des applications</h1>
|
|||
|
<p>Gestion des permissions
|
|||
|
———————–
|
|||
|
###Comment gérer les permissions des applications</p>
|
|||
|
<ul>
|
|||
|
<li><em>Paramètres</em> → <em>Applications</em> → <em>Paramètres</em> → <em>Autorisation des applications</em> ;</li>
|
|||
|
<li>autorisez le moins de permissions possible aux applications ;)
|
|||
|
<img src="https://image.noelshack.com/fichiers/2018/22/7/1528025786-screenshot-2018-05-30-android-acceder-menu-permissions-applications.gif" alt="screenshot-2018_05_30-Android-Acceder_menu_permissions_applications" /></li>
|
|||
|
</ul>
|
|||
|
|
|||
|
<p>###L’utilisation de données forgées (<em>fake data</em>) pour les applications demandant trop de permissions
|
|||
|
<a href="https://forum.xda-developers.com/xposed/modules/xprivacylua6-0-android-privacy-manager-t3730663">XPrivacyLua</a> (pour Android 6 ou plus) ou <a href="https://forum.xda-developers.com/xposed/modules/xprivacy-ultimate-android-privacy-app-t2320783">XPrivacy</a> (pour Android 5 ou moins) permet de leurrer les applications. Si vous êtes obligé d’installer une application demandant trop de permissions, c’est fait pour vous. <strong>L’accès super‐utilisateur (<em>root</em>) est obligatoire.</strong>
|
|||
|
<img src="https://image.noelshack.com/fichiers/2018/22/7/1528025833-xprivacy.png" alt="screenshot XPrivacy" /></p>
|
|||
|
|
|||
|
<p>###Supprimer ou restreindre les permissions d’une application
|
|||
|
<a href="https://fr.wikipedia.org/wiki/Lucky_Patcher">Lucky Patcher</a> peut être utilisé pour supprimer des permissions à une application. C’est au niveau de l’application que la modification sera appliquée et donc peu importe les autorisations accordées par le système. Cela peut, bien entendu, provoquer des instabilités voire des dysfonctionnements des applications modifiées et des applications qui dépendent d’elles.</p>
|
|||
|
|
|||
|
<h2 id="gérer-le-démarrage-des-applications">Gérer le démarrage des applications.</h2>
|
|||
|
<p>Lors de leur installation ou de leur paramétrage, les applications peuvent « demander » à Android de les lancer lorsqu’il y a certains évènements : démarrage (<em>boot</em>) de la machine, connexion à Internet en Wi‐Fi ou par le réseau opérateur, extinction de la machine, etc. Vous pouvez utiliser l’application libre <a href="https://f-droid.org/wiki/index.php?title=com.elsdoerfer.android.autostart">Autostarts</a> (ou via <a href="https://play.google.com/store/apps/details?id=com.elsdoerfer.android.autostarts">PlayStore/Yalp</a>) pour gérer quelle application peut démarrer en fonction de quel type d’évènement. Si vous avez installé <a href="https://f-droid.org/en/packages/de.robv.android.xposed.installer/">XPosed Framework</a>, à la place d’autostart vous pouvez installer et utiliser son <a href="http://repo.xposed.info/module/de.defim.apk.bootmanager">module BootManager</a> selon vos préférences (<strong>l’accès super‐utilisateur <em>root</em> est obligatoire</strong>).
|
|||
|
<img src="https://image.noelshack.com/fichiers/2018/22/7/1528025872-android-autostarts-demo.gif" alt="Android-Autostarts-Demo" /></p>
|
|||
|
|
|||
|
<h2 id="forcer-la-suppression-dapplications">Forcer la suppression d’applications</h2>
|
|||
|
<p>Certaines applications comme Facebook, AVG et compagnie sont installées par les opérateurs (contre rétribution) avec blocage pour empêcher l’utilisateur final de les désinstaller. Pour contrer cela, vous pouvez utiliser <a href="https://fr.wikipedia.org/wiki/Lucky_Patcher">Lucky Patcher</a>, il permet de forcer la désinstallation d’applications, la suppression de publicité et autres bidouilles (<strong>l’accès super‐utilisateur <em>root</em> est obligatoire</strong>).
|
|||
|
Pour supprimer une application vous n’avez qu’à lancer Lucky Patcher, chercher ladite application, cliquer dessus puis choisir <em>Désinstaller l’application</em>.
|
|||
|
<strong>Attention :</strong> avant de supprimer une application vérifiez que votre système ou d’autres applications n’en dépendent pas. Pour ce faire, désactivez‐la, vérifiez si aucune erreur ne se produit avec les autres applications ou pire le système Android. Ensuite, redémarrez votre machine et si toujours aucune erreur ne se produit, alors vous pouvez la supprimer. Pensez à faire une sauvegarde de l’application afin de pouvoir la restaurer en cas de problème. <strong>Ne supprimez pas les applications des fabricants et opérateurs ni les applications système, car vous risquez un <em><a href="https://fr.wikipedia.org/wiki/Bootloop">bootloop</a></em> !</strong></p>
|
|||
|
|
|||
|
<p><img src="https://image.noelshack.com/fichiers/2018/22/7/1528026352-screenshot-2018-06-01-luckypatcher-remove-application.gif" alt="Démo de suppression d’application Android avec Lucky Patcher" /></p>
|
|||
|
|
|||
|
<p><img src="https://image.noelshack.com/fichiers/2018/22/7/1528026394-android-luckypatcher-demo.gif" alt="Démo de l’application Android Lucky Patcher" /></p>
|
|||
|
|
|||
|
<h1 id="les-applications-de-rencontre">Les applications de rencontre</h1>
|
|||
|
<p><img src="https://image.noelshack.com/fichiers/2018/22/7/1528026440-alice-wanted-dark-disney-disney-cruiseplan.gif" alt="Alice au pays des merveilles" /></p>
|
|||
|
|
|||
|
<p>Si vous avez moins de trente ans, c’est <strong>la</strong> catégorie qui pompe vos données personnelles et qui pourtant reste incontournable. En revanche, dans cette catégorie, n’espérez pas, il n’y a pas encore d’application de rencontre libre ni sans espionnage. Donc, voyons comment sauver vos miches sans vous empêcher de tchatcher.</p>
|
|||
|
|
|||
|
<h2 id="les-applications-de-rencontre-généralistes-badoo-facebook-meetic-tinder">Les applications de rencontre généralistes (Badoo, Facebook, Meetic, Tinder…)</h2>
|
|||
|
<p><strong>Note :</strong> elles dépendent beaucoup de <a href="https://en.wikipedia.org/wiki/Google_Play_Services">Google Play Service</a>. Elles n’apprécient pas trop <a href="https://guardianproject.info/apps/orbot/">Orbot</a>.</p>
|
|||
|
|
|||
|
<p>Elles n’ont pas besoin de la Géolocalisation (sauf si vous utilisez une fonctionnalité basée dessus).
|
|||
|
Sur les versions d’Android permettant la gestion des permissions, vous pouvez leur verrouiller l’accès à quasi tout sans qu’elles cessent de fonctionner. Pour les Android plus vieux, il faudra passer par <a href="https://forum.xda-developers.com/xposed/modules/xprivacy-ultimate-android-privacy-app-t2320783">XPrivacy</a>, comme expliqué plus haut. S’il faut vraiment autoriser des permissions contraignantes (par exemple, l’accès à l’identifiant de l’appareil), passez par <a href="https://forum.xda-developers.com/xposed/modules/xprivacylua6-0-android-privacy-manager-t3730663">XPrivacyLUA</a>.
|
|||
|
Pensez autant que faire se peut à supprimer les méta‐données de vos photos via, par exemple, Scrambled Exif (<a href="https://f-droid.org/en/packages/com.jarsilio.android.scrambledeggsif/">sur F-Droid</a> ou sur <a href="https://play.google.com/store/apps/details?id=com.jarsilio.android.scrambledeggsif">Google PlayStore</a>). N’oubliez pas que les autres utilisateurs peuvent facilement recopier vos photos et les utiliser pour faire de faux comptes. ;)</p>
|
|||
|
|
|||
|
<h2 id="les-applications-basées-sur-la-géolocalisation-happn-meetwo-theleague">Les applications basées sur la Géolocalisation (Happn, Meetwo, The League…)</h2>
|
|||
|
<p><strong>Note :</strong> elles dépendent beaucoup de <a href="https://en.wikipedia.org/wiki/Google_Play_Services">Google Play Service</a>. Elles n’apprécient pas trop <a href="https://guardianproject.info/apps/orbot/">Orbot</a>.</p>
|
|||
|
|
|||
|
<p>Après utilisation, bien penser à <em>Forcer l’arrêt</em> de l’application dans le menu <em>Application</em> d’Android ou <em>a minima</em> de couper la géolocalisation. Pour répondre aux <em>Matches</em>, il faut que l’application soit lancée et connectée à Internet, mais pas besoin de la géolocalisation pour cela.</p>
|
|||
|
|
|||
|
<h1 id="lutter-contre-les-vols">Lutter contre les vols</h1>
|
|||
|
<p>Géolocalisation
|
|||
|
—————
|
|||
|
<strong>Note :</strong> peut avoir une incidence sur la batterie et la charge réseau selon la configuration.</p>
|
|||
|
|
|||
|
<p>Vous pouvez régler un logiciel comme <a href="https://gpslogger.app/">GPSLogger</a> pour exporter la <a href="https://fr.wikipedia.org/wiki/Geolocalisation">géolocalisation</a> de votre appareil en permanence ou uniquement lors du redémarrage de votre appareil.
|
|||
|
Si vous disposez d’un compte sur un serveur <a href="https://fr.wikipedia.org/wiki/Nextcloud">Nextcloud</a> ou <a href="https://fr.wikipedia.org/wiki/Owncloud">Owncloud</a>, vous pouvez suivre ce tutoriel: <a href="https://www.0rion.netlib.re/forum4/viewtopic.php?f=93&t=748"><em>Exporter géolocalisation sur le cloud (Nextcloud/Owncloud) avec GpsLogger</em></a>.</p>
|
|||
|
|
|||
|
<h2 id="utiliser-des-mots-de-passe-dapplication-token-ou-encore-apikey">Utiliser des « mots de passe d’application » (Token ou encore API Key)</h2>
|
|||
|
<p>Certains services, comme Nextcloud, permettent de créer des mots de passe uniques permettant d’être utilisés par une seule (ou plusieurs) applications. Ainsi, en cas de vol, on pourrait éventuellement récupérer votre mot de passe d’application, mais pas le vrai mot de passe de votre compte (ni des éventuels autres services sur lesquels vous pourriez avoir réutilisé ce mot de passe). Utilisez autant que faire se peut ce mécanisme et, en cas de vol/piratage, allez révoquer directement les accès compromis et ce le plus vite possible.
|
|||
|
<img src="https://image.noelshack.com/fichiers/2018/23/3/1528241705-exemple-nextcloud-connexion-via-jeton.gif" alt="Exemple Nextcloud de connexion via un jeton" /></p>
|
|||
|
|
|||
|
<h2 id="laccès-à-distance">L’accès à distance</h2>
|
|||
|
<p><strong>Note :</strong> a une incidence sur la batterie et la charge réseau.</p>
|
|||
|
|
|||
|
<p>Certaines applications vous permettent de contrôler votre appareil Android à distance (depuis un ordinateur). La plus connue est <a href="https://www.airdroid.com/fr/index.html">AirDroid</a>, hélas non libre et pas des plus saines (l’application permettant un contrôle depuis le site de l’entreprise). Il n’existe actuellement aucune alternative libre.</p>
|
|||
|
|
|||
|
</div>
|
|||
|
|
|||
|
|
|||
|
|
|||
|
<div class="d-print-none"><footer class="article__footer"><meta itemprop="dateModified" content="2019-12-25T00:00:00+01:00"><!-- start custom article footer snippet -->
|
|||
|
|
|||
|
<!-- end custom article footer snippet -->
|
|||
|
<!--
|
|||
|
<div align="right"><a type="application/rss+xml" href="/feed.xml" title="S'abonner"><i class="fa fa-rss fa-2x"></i></a>
|
|||
|
|
|||
|
 </div>
|
|||
|
-->
|
|||
|
</footer>
|
|||
|
<div class="article__section-navigator clearfix"><div class="previous"><span>PRÉCÉDENT</span><a href="/2019/12/25/un-vrai-coffre-fort-numerique_2017-06-12T21_56_39.html">un-vrai-coffre-fort-numerique_2017-06-12T21_56_39</a></div><div class="next"><span>SUIVANT</span><a href="/2019/12/25/virtualbox-AdditionsInvit%C3%A9Debian.html">virtualbox-AdditionsInvitéDebian</a></div></div></div>
|
|||
|
|
|||
|
</div>
|
|||
|
|
|||
|
<script>(function() {
|
|||
|
var SOURCES = window.TEXT_VARIABLES.sources;
|
|||
|
window.Lazyload.js(SOURCES.jquery, function() {
|
|||
|
$(function() {
|
|||
|
var $this ,$scroll;
|
|||
|
var $articleContent = $('.js-article-content');
|
|||
|
var hasSidebar = $('.js-page-root').hasClass('layout--page--sidebar');
|
|||
|
var scroll = hasSidebar ? '.js-page-main' : 'html, body';
|
|||
|
$scroll = $(scroll);
|
|||
|
|
|||
|
$articleContent.find('.highlight').each(function() {
|
|||
|
$this = $(this);
|
|||
|
$this.attr('data-lang', $this.find('code').attr('data-lang'));
|
|||
|
});
|
|||
|
$articleContent.find('h1[id], h2[id], h3[id], h4[id], h5[id], h6[id]').each(function() {
|
|||
|
$this = $(this);
|
|||
|
$this.append($('<a class="anchor d-print-none" aria-hidden="true"></a>').html('<i class="fas fa-anchor"></i>'));
|
|||
|
});
|
|||
|
$articleContent.on('click', '.anchor', function() {
|
|||
|
$scroll.scrollToAnchor('#' + $(this).parent().attr('id'), 400);
|
|||
|
});
|
|||
|
});
|
|||
|
});
|
|||
|
})();
|
|||
|
</script>
|
|||
|
|
|||
|
</div><section class="page__comments d-print-none"></section></article><!-- start custom main bottom snippet -->
|
|||
|
<!-- end custom main bottom snippet -->
|
|||
|
</div>
|
|||
|
</div></div></div></div>
|
|||
|
</div><script>(function() {
|
|||
|
var SOURCES = window.TEXT_VARIABLES.sources;
|
|||
|
window.Lazyload.js(SOURCES.jquery, function() {
|
|||
|
var $body = $('body'), $window = $(window);
|
|||
|
var $pageRoot = $('.js-page-root'), $pageMain = $('.js-page-main');
|
|||
|
var activeCount = 0;
|
|||
|
function modal(options) {
|
|||
|
var $root = this, visible, onChange, hideWhenWindowScroll = false;
|
|||
|
var scrollTop;
|
|||
|
function setOptions(options) {
|
|||
|
var _options = options || {};
|
|||
|
visible = _options.initialVisible === undefined ? false : show;
|
|||
|
onChange = _options.onChange;
|
|||
|
hideWhenWindowScroll = _options.hideWhenWindowScroll;
|
|||
|
}
|
|||
|
function init() {
|
|||
|
setState(visible);
|
|||
|
}
|
|||
|
function setState(isShow) {
|
|||
|
if (isShow === visible) {
|
|||
|
return;
|
|||
|
}
|
|||
|
visible = isShow;
|
|||
|
if (visible) {
|
|||
|
activeCount++;
|
|||
|
scrollTop = $(window).scrollTop() || $pageMain.scrollTop();
|
|||
|
$root.addClass('modal--show');
|
|||
|
$pageMain.scrollTop(scrollTop);
|
|||
|
activeCount === 1 && ($pageRoot.addClass('show-modal'), $body.addClass('of-hidden'));
|
|||
|
hideWhenWindowScroll && window.hasEvent('touchstart') && $window.on('scroll', hide);
|
|||
|
$window.on('keyup', handleKeyup);
|
|||
|
} else {
|
|||
|
activeCount > 0 && activeCount--;
|
|||
|
$root.removeClass('modal--show');
|
|||
|
$window.scrollTop(scrollTop);
|
|||
|
activeCount === 0 && ($pageRoot.removeClass('show-modal'), $body.removeClass('of-hidden'));
|
|||
|
hideWhenWindowScroll && window.hasEvent('touchstart') && $window.off('scroll', hide);
|
|||
|
$window.off('keyup', handleKeyup);
|
|||
|
}
|
|||
|
onChange && onChange(visible);
|
|||
|
}
|
|||
|
function show() {
|
|||
|
setState(true);
|
|||
|
}
|
|||
|
function hide() {
|
|||
|
setState(false);
|
|||
|
}
|
|||
|
function handleKeyup(e) {
|
|||
|
// Char Code: 27 ESC
|
|||
|
if (e.which === 27) {
|
|||
|
hide();
|
|||
|
}
|
|||
|
}
|
|||
|
setOptions(options);
|
|||
|
init();
|
|||
|
return {
|
|||
|
show: show,
|
|||
|
hide: hide,
|
|||
|
$el: $root
|
|||
|
};
|
|||
|
}
|
|||
|
$.fn.modal = modal;
|
|||
|
});
|
|||
|
})();
|
|||
|
</script><div class="modal modal--overflow page__search-modal d-print-none js-page-search-modal"><script>
|
|||
|
(function () {
|
|||
|
var SOURCES = window.TEXT_VARIABLES.sources;
|
|||
|
window.Lazyload.js(SOURCES.jquery, function() {
|
|||
|
// search panel
|
|||
|
var search = (window.search || (window.search = {}));
|
|||
|
var useDefaultSearchBox = window.useDefaultSearchBox === undefined ?
|
|||
|
true : window.useDefaultSearchBox ;
|
|||
|
|
|||
|
var $searchModal = $('.js-page-search-modal');
|
|||
|
var $searchToggle = $('.js-search-toggle');
|
|||
|
var searchModal = $searchModal.modal({ onChange: handleModalChange, hideWhenWindowScroll: true });
|
|||
|
var modalVisible = false;
|
|||
|
search.searchModal = searchModal;
|
|||
|
|
|||
|
var $searchBox = null;
|
|||
|
var $searchInput = null;
|
|||
|
var $searchClear = null;
|
|||
|
|
|||
|
function getModalVisible() {
|
|||
|
return modalVisible;
|
|||
|
}
|
|||
|
search.getModalVisible = getModalVisible;
|
|||
|
|
|||
|
function handleModalChange(visible) {
|
|||
|
modalVisible = visible;
|
|||
|
if (visible) {
|
|||
|
search.onShow && search.onShow();
|
|||
|
useDefaultSearchBox && $searchInput[0] && $searchInput[0].focus();
|
|||
|
} else {
|
|||
|
search.onShow && search.onHide();
|
|||
|
useDefaultSearchBox && $searchInput[0] && $searchInput[0].blur();
|
|||
|
setTimeout(function() {
|
|||
|
useDefaultSearchBox && ($searchInput.val(''), $searchBox.removeClass('not-empty'));
|
|||
|
search.clear && search.clear();
|
|||
|
window.pageAsideAffix && window.pageAsideAffix.refresh();
|
|||
|
}, 400);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
$searchToggle.on('click', function() {
|
|||
|
modalVisible ? searchModal.hide() : searchModal.show();
|
|||
|
});
|
|||
|
// Char Code: 83 S, 191 /
|
|||
|
$(window).on('keyup', function(e) {
|
|||
|
if (!modalVisible && !window.isFormElement(e.target || e.srcElement) && (e.which === 83 || e.which === 191)) {
|
|||
|
modalVisible || searchModal.show();
|
|||
|
}
|
|||
|
});
|
|||
|
|
|||
|
if (useDefaultSearchBox) {
|
|||
|
$searchBox = $('.js-search-box');
|
|||
|
$searchInput = $searchBox.children('input');
|
|||
|
$searchClear = $searchBox.children('.js-icon-clear');
|
|||
|
search.getSearchInput = function() {
|
|||
|
return $searchInput.get(0);
|
|||
|
};
|
|||
|
search.getVal = function() {
|
|||
|
return $searchInput.val();
|
|||
|
};
|
|||
|
search.setVal = function(val) {
|
|||
|
$searchInput.val(val);
|
|||
|
};
|
|||
|
|
|||
|
$searchInput.on('focus', function() {
|
|||
|
$(this).addClass('focus');
|
|||
|
});
|
|||
|
$searchInput.on('blur', function() {
|
|||
|
$(this).removeClass('focus');
|
|||
|
});
|
|||
|
$searchInput.on('input', window.throttle(function() {
|
|||
|
var val = $(this).val();
|
|||
|
if (val === '' || typeof val !== 'string') {
|
|||
|
search.clear && search.clear();
|
|||
|
} else {
|
|||
|
$searchBox.addClass('not-empty');
|
|||
|
search.onInputNotEmpty && search.onInputNotEmpty(val);
|
|||
|
}
|
|||
|
}, 400));
|
|||
|
$searchClear.on('click', function() {
|
|||
|
$searchInput.val(''); $searchBox.removeClass('not-empty');
|
|||
|
search.clear && search.clear();
|
|||
|
});
|
|||
|
}
|
|||
|
});
|
|||
|
})();
|
|||
|
</script><div class="search search--dark">
|
|||
|
<div class="main">
|
|||
|
<div class="search__header">Recherche</div>
|
|||
|
<div class="search-bar">
|
|||
|
<div class="search-box js-search-box">
|
|||
|
<div class="search-box__icon-search"><i class="fas fa-search"></i></div>
|
|||
|
<input id="search-input" type="text" />
|
|||
|
<div class="search-box__icon-clear js-icon-clear">
|
|||
|
<a><i class="fas fa-times"></i></a>
|
|||
|
</div>
|
|||
|
</div>
|
|||
|
<button class="button button--theme-dark button--pill search__cancel js-search-toggle">
|
|||
|
Annuler</button>
|
|||
|
</div>
|
|||
|
<div id="results-container" class="search-result js-search-result"></div>
|
|||
|
</div>
|
|||
|
</div>
|
|||
|
<!-- Script pointing to search-script.js -->
|
|||
|
<script>/*!
|
|||
|
* Simple-Jekyll-Search
|
|||
|
* Copyright 2015-2020, Christian Fei
|
|||
|
* Licensed under the MIT License.
|
|||
|
*/
|
|||
|
|
|||
|
(function(){
|
|||
|
'use strict'
|
|||
|
|
|||
|
var _$Templater_7 = {
|
|||
|
compile: compile,
|
|||
|
setOptions: setOptions
|
|||
|
}
|
|||
|
|
|||
|
const options = {}
|
|||
|
options.pattern = /\{(.*?)\}/g
|
|||
|
options.template = ''
|
|||
|
options.middleware = function () {}
|
|||
|
|
|||
|
function setOptions (_options) {
|
|||
|
options.pattern = _options.pattern || options.pattern
|
|||
|
options.template = _options.template || options.template
|
|||
|
if (typeof _options.middleware === 'function') {
|
|||
|
options.middleware = _options.middleware
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
function compile (data) {
|
|||
|
return options.template.replace(options.pattern, function (match, prop) {
|
|||
|
const value = options.middleware(prop, data[prop], options.template)
|
|||
|
if (typeof value !== 'undefined') {
|
|||
|
return value
|
|||
|
}
|
|||
|
return data[prop] || match
|
|||
|
})
|
|||
|
}
|
|||
|
|
|||
|
'use strict';
|
|||
|
|
|||
|
function fuzzysearch (needle, haystack) {
|
|||
|
var tlen = haystack.length;
|
|||
|
var qlen = needle.length;
|
|||
|
if (qlen > tlen) {
|
|||
|
return false;
|
|||
|
}
|
|||
|
if (qlen === tlen) {
|
|||
|
return needle === haystack;
|
|||
|
}
|
|||
|
outer: for (var i = 0, j = 0; i < qlen; i++) {
|
|||
|
var nch = needle.charCodeAt(i);
|
|||
|
while (j < tlen) {
|
|||
|
if (haystack.charCodeAt(j++) === nch) {
|
|||
|
continue outer;
|
|||
|
}
|
|||
|
}
|
|||
|
return false;
|
|||
|
}
|
|||
|
return true;
|
|||
|
}
|
|||
|
|
|||
|
var _$fuzzysearch_1 = fuzzysearch;
|
|||
|
|
|||
|
'use strict'
|
|||
|
|
|||
|
/* removed: const _$fuzzysearch_1 = require('fuzzysearch') */;
|
|||
|
|
|||
|
var _$FuzzySearchStrategy_5 = new FuzzySearchStrategy()
|
|||
|
|
|||
|
function FuzzySearchStrategy () {
|
|||
|
this.matches = function (string, crit) {
|
|||
|
return _$fuzzysearch_1(crit.toLowerCase(), string.toLowerCase())
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
'use strict'
|
|||
|
|
|||
|
var _$LiteralSearchStrategy_6 = new LiteralSearchStrategy()
|
|||
|
|
|||
|
function LiteralSearchStrategy () {
|
|||
|
this.matches = function (str, crit) {
|
|||
|
if (!str) return false
|
|||
|
|
|||
|
str = str.trim().toLowerCase()
|
|||
|
crit = crit.trim().toLowerCase()
|
|||
|
|
|||
|
return crit.split(' ').filter(function (word) {
|
|||
|
return str.indexOf(word) >= 0
|
|||
|
}).length === crit.split(' ').length
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
'use strict'
|
|||
|
|
|||
|
var _$Repository_4 = {
|
|||
|
put: put,
|
|||
|
clear: clear,
|
|||
|
search: search,
|
|||
|
setOptions: __setOptions_4
|
|||
|
}
|
|||
|
|
|||
|
/* removed: const _$FuzzySearchStrategy_5 = require('./SearchStrategies/FuzzySearchStrategy') */;
|
|||
|
/* removed: const _$LiteralSearchStrategy_6 = require('./SearchStrategies/LiteralSearchStrategy') */;
|
|||
|
|
|||
|
function NoSort () {
|
|||
|
return 0
|
|||
|
}
|
|||
|
|
|||
|
const data = []
|
|||
|
let opt = {}
|
|||
|
|
|||
|
opt.fuzzy = false
|
|||
|
opt.limit = 10
|
|||
|
opt.searchStrategy = opt.fuzzy ? _$FuzzySearchStrategy_5 : _$LiteralSearchStrategy_6
|
|||
|
opt.sort = NoSort
|
|||
|
opt.exclude = []
|
|||
|
|
|||
|
function put (data) {
|
|||
|
if (isObject(data)) {
|
|||
|
return addObject(data)
|
|||
|
}
|
|||
|
if (isArray(data)) {
|
|||
|
return addArray(data)
|
|||
|
}
|
|||
|
return undefined
|
|||
|
}
|
|||
|
function clear () {
|
|||
|
data.length = 0
|
|||
|
return data
|
|||
|
}
|
|||
|
|
|||
|
function isObject (obj) {
|
|||
|
return Boolean(obj) && Object.prototype.toString.call(obj) === '[object Object]'
|
|||
|
}
|
|||
|
|
|||
|
function isArray (obj) {
|
|||
|
return Boolean(obj) && Object.prototype.toString.call(obj) === '[object Array]'
|
|||
|
}
|
|||
|
|
|||
|
function addObject (_data) {
|
|||
|
data.push(_data)
|
|||
|
return data
|
|||
|
}
|
|||
|
|
|||
|
function addArray (_data) {
|
|||
|
const added = []
|
|||
|
clear()
|
|||
|
for (let i = 0, len = _data.length; i < len; i++) {
|
|||
|
if (isObject(_data[i])) {
|
|||
|
added.push(addObject(_data[i]))
|
|||
|
}
|
|||
|
}
|
|||
|
return added
|
|||
|
}
|
|||
|
|
|||
|
function search (crit) {
|
|||
|
if (!crit) {
|
|||
|
return []
|
|||
|
}
|
|||
|
return findMatches(data, crit, opt.searchStrategy, opt).sort(opt.sort)
|
|||
|
}
|
|||
|
|
|||
|
function __setOptions_4 (_opt) {
|
|||
|
opt = _opt || {}
|
|||
|
|
|||
|
opt.fuzzy = _opt.fuzzy || false
|
|||
|
opt.limit = _opt.limit || 10
|
|||
|
opt.searchStrategy = _opt.fuzzy ? _$FuzzySearchStrategy_5 : _$LiteralSearchStrategy_6
|
|||
|
opt.sort = _opt.sort || NoSort
|
|||
|
opt.exclude = _opt.exclude || []
|
|||
|
}
|
|||
|
|
|||
|
function findMatches (data, crit, strategy, opt) {
|
|||
|
const matches = []
|
|||
|
for (let i = 0; i < data.length && matches.length < opt.limit; i++) {
|
|||
|
const match = findMatchesInObject(data[i], crit, strategy, opt)
|
|||
|
if (match) {
|
|||
|
matches.push(match)
|
|||
|
}
|
|||
|
}
|
|||
|
return matches
|
|||
|
}
|
|||
|
|
|||
|
function findMatchesInObject (obj, crit, strategy, opt) {
|
|||
|
for (const key in obj) {
|
|||
|
if (!isExcluded(obj[key], opt.exclude) && strategy.matches(obj[key], crit)) {
|
|||
|
return obj
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
function isExcluded (term, excludedTerms) {
|
|||
|
for (let i = 0, len = excludedTerms.length; i < len; i++) {
|
|||
|
const excludedTerm = excludedTerms[i]
|
|||
|
if (new RegExp(excludedTerm).test(term)) {
|
|||
|
return true
|
|||
|
}
|
|||
|
}
|
|||
|
return false
|
|||
|
}
|
|||
|
|
|||
|
/* globals ActiveXObject:false */
|
|||
|
|
|||
|
'use strict'
|
|||
|
|
|||
|
var _$JSONLoader_2 = {
|
|||
|
load: load
|
|||
|
}
|
|||
|
|
|||
|
function load (location, callback) {
|
|||
|
const xhr = getXHR()
|
|||
|
xhr.open('GET', location, true)
|
|||
|
xhr.onreadystatechange = createStateChangeListener(xhr, callback)
|
|||
|
xhr.send()
|
|||
|
}
|
|||
|
|
|||
|
function createStateChangeListener (xhr, callback) {
|
|||
|
return function () {
|
|||
|
if (xhr.readyState === 4 && xhr.status === 200) {
|
|||
|
try {
|
|||
|
callback(null, JSON.parse(xhr.responseText))
|
|||
|
} catch (err) {
|
|||
|
callback(err, null)
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
function getXHR () {
|
|||
|
return window.XMLHttpRequest ? new window.XMLHttpRequest() : new ActiveXObject('Microsoft.XMLHTTP')
|
|||
|
}
|
|||
|
|
|||
|
'use strict'
|
|||
|
|
|||
|
var _$OptionsValidator_3 = function OptionsValidator (params) {
|
|||
|
if (!validateParams(params)) {
|
|||
|
throw new Error('-- OptionsValidator: required options missing')
|
|||
|
}
|
|||
|
|
|||
|
if (!(this instanceof OptionsValidator)) {
|
|||
|
return new OptionsValidator(params)
|
|||
|
}
|
|||
|
|
|||
|
const requiredOptions = params.required
|
|||
|
|
|||
|
this.getRequiredOptions = function () {
|
|||
|
return requiredOptions
|
|||
|
}
|
|||
|
|
|||
|
this.validate = function (parameters) {
|
|||
|
const errors = []
|
|||
|
requiredOptions.forEach(function (requiredOptionName) {
|
|||
|
if (typeof parameters[requiredOptionName] === 'undefined') {
|
|||
|
errors.push(requiredOptionName)
|
|||
|
}
|
|||
|
})
|
|||
|
return errors
|
|||
|
}
|
|||
|
|
|||
|
function validateParams (params) {
|
|||
|
if (!params) {
|
|||
|
return false
|
|||
|
}
|
|||
|
return typeof params.required !== 'undefined' && params.required instanceof Array
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
'use strict'
|
|||
|
|
|||
|
var _$utils_9 = {
|
|||
|
merge: merge,
|
|||
|
isJSON: isJSON
|
|||
|
}
|
|||
|
|
|||
|
function merge (defaultParams, mergeParams) {
|
|||
|
const mergedOptions = {}
|
|||
|
for (const option in defaultParams) {
|
|||
|
mergedOptions[option] = defaultParams[option]
|
|||
|
if (typeof mergeParams[option] !== 'undefined') {
|
|||
|
mergedOptions[option] = mergeParams[option]
|
|||
|
}
|
|||
|
}
|
|||
|
return mergedOptions
|
|||
|
}
|
|||
|
|
|||
|
function isJSON (json) {
|
|||
|
try {
|
|||
|
if (json instanceof Object && JSON.parse(JSON.stringify(json))) {
|
|||
|
return true
|
|||
|
}
|
|||
|
return false
|
|||
|
} catch (err) {
|
|||
|
return false
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
var _$src_8 = {};
|
|||
|
(function (window) {
|
|||
|
'use strict'
|
|||
|
|
|||
|
let options = {
|
|||
|
searchInput: null,
|
|||
|
resultsContainer: null,
|
|||
|
json: [],
|
|||
|
success: Function.prototype,
|
|||
|
searchResultTemplate: '<li><a href="{url}" title="{desc}">{title}</a></li>',
|
|||
|
templateMiddleware: Function.prototype,
|
|||
|
sortMiddleware: function () {
|
|||
|
return 0
|
|||
|
},
|
|||
|
noResultsText: 'No results found',
|
|||
|
limit: 10,
|
|||
|
fuzzy: false,
|
|||
|
debounceTime: null,
|
|||
|
exclude: []
|
|||
|
}
|
|||
|
|
|||
|
let debounceTimerHandle
|
|||
|
const debounce = function (func, delayMillis) {
|
|||
|
if (delayMillis) {
|
|||
|
clearTimeout(debounceTimerHandle)
|
|||
|
debounceTimerHandle = setTimeout(func, delayMillis)
|
|||
|
} else {
|
|||
|
func.call()
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
const requiredOptions = ['searchInput', 'resultsContainer', 'json']
|
|||
|
|
|||
|
/* removed: const _$Templater_7 = require('./Templater') */;
|
|||
|
/* removed: const _$Repository_4 = require('./Repository') */;
|
|||
|
/* removed: const _$JSONLoader_2 = require('./JSONLoader') */;
|
|||
|
const optionsValidator = _$OptionsValidator_3({
|
|||
|
required: requiredOptions
|
|||
|
})
|
|||
|
/* removed: const _$utils_9 = require('./utils') */;
|
|||
|
|
|||
|
window.SimpleJekyllSearch = function (_options) {
|
|||
|
const errors = optionsValidator.validate(_options)
|
|||
|
if (errors.length > 0) {
|
|||
|
throwError('You must specify the following required options: ' + requiredOptions)
|
|||
|
}
|
|||
|
|
|||
|
options = _$utils_9.merge(options, _options)
|
|||
|
|
|||
|
_$Templater_7.setOptions({
|
|||
|
template: options.searchResultTemplate,
|
|||
|
middleware: options.templateMiddleware
|
|||
|
})
|
|||
|
|
|||
|
_$Repository_4.setOptions({
|
|||
|
fuzzy: options.fuzzy,
|
|||
|
limit: options.limit,
|
|||
|
sort: options.sortMiddleware,
|
|||
|
exclude: options.exclude
|
|||
|
})
|
|||
|
|
|||
|
if (_$utils_9.isJSON(options.json)) {
|
|||
|
initWithJSON(options.json)
|
|||
|
} else {
|
|||
|
initWithURL(options.json)
|
|||
|
}
|
|||
|
|
|||
|
const rv = {
|
|||
|
search: search
|
|||
|
}
|
|||
|
|
|||
|
typeof options.success === 'function' && options.success.call(rv)
|
|||
|
return rv
|
|||
|
}
|
|||
|
|
|||
|
function initWithJSON (json) {
|
|||
|
_$Repository_4.put(json)
|
|||
|
registerInput()
|
|||
|
}
|
|||
|
|
|||
|
function initWithURL (url) {
|
|||
|
_$JSONLoader_2.load(url, function (err, json) {
|
|||
|
if (err) {
|
|||
|
throwError('failed to get JSON (' + url + ')')
|
|||
|
}
|
|||
|
initWithJSON(json)
|
|||
|
})
|
|||
|
}
|
|||
|
|
|||
|
function emptyResultsContainer () {
|
|||
|
options.resultsContainer.innerHTML = ''
|
|||
|
}
|
|||
|
|
|||
|
function appendToResultsContainer (text) {
|
|||
|
options.resultsContainer.innerHTML += text
|
|||
|
}
|
|||
|
|
|||
|
function registerInput () {
|
|||
|
options.searchInput.addEventListener('input', function (e) {
|
|||
|
if (isWhitelistedKey(e.which)) {
|
|||
|
emptyResultsContainer()
|
|||
|
debounce(function () { search(e.target.value) }, options.debounceTime)
|
|||
|
}
|
|||
|
})
|
|||
|
}
|
|||
|
|
|||
|
function search (query) {
|
|||
|
if (isValidQuery(query)) {
|
|||
|
emptyResultsContainer()
|
|||
|
render(_$Repository_4.search(query), query)
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
function render (results, query) {
|
|||
|
const len = results.length
|
|||
|
if (len === 0) {
|
|||
|
return appendToResultsContainer(options.noResultsText)
|
|||
|
}
|
|||
|
for (let i = 0; i < len; i++) {
|
|||
|
results[i].query = query
|
|||
|
appendToResultsContainer(_$Templater_7.compile(results[i]))
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
function isValidQuery (query) {
|
|||
|
return query && query.length > 0
|
|||
|
}
|
|||
|
|
|||
|
function isWhitelistedKey (key) {
|
|||
|
return [13, 16, 20, 37, 38, 39, 40, 91].indexOf(key) === -1
|
|||
|
}
|
|||
|
|
|||
|
function throwError (message) {
|
|||
|
throw new Error('SimpleJekyllSearch --- ' + message)
|
|||
|
}
|
|||
|
})(window)
|
|||
|
|
|||
|
}());
|
|||
|
</script>
|
|||
|
|
|||
|
<!-- Configuration -->
|
|||
|
<script>
|
|||
|
SimpleJekyllSearch({
|
|||
|
searchInput: document.getElementById('search-input'),
|
|||
|
resultsContainer: document.getElementById('results-container'),
|
|||
|
noResultsText: '<p>Aucun résultat!</p>',
|
|||
|
json: '/search.json',
|
|||
|
searchResultTemplate: '<li><a href="{url}">{date} {title}</a> (Création {create})</li>'
|
|||
|
})
|
|||
|
</script>
|
|||
|
|
|||
|
</div></div>
|
|||
|
|
|||
|
|
|||
|
<script>(function() {
|
|||
|
var SOURCES = window.TEXT_VARIABLES.sources;
|
|||
|
window.Lazyload.js(SOURCES.jquery, function() {
|
|||
|
function scrollToAnchor(anchor, duration, callback) {
|
|||
|
var $root = this;
|
|||
|
$root.animate({ scrollTop: $(anchor).position().top }, duration, function() {
|
|||
|
window.history.replaceState(null, '', window.location.href.split('#')[0] + anchor);
|
|||
|
callback && callback();
|
|||
|
});
|
|||
|
}
|
|||
|
$.fn.scrollToAnchor = scrollToAnchor;
|
|||
|
});
|
|||
|
})();
|
|||
|
(function() {
|
|||
|
var SOURCES = window.TEXT_VARIABLES.sources;
|
|||
|
window.Lazyload.js(SOURCES.jquery, function() {
|
|||
|
function affix(options) {
|
|||
|
var $root = this, $window = $(window), $scrollTarget, $scroll,
|
|||
|
offsetBottom = 0, scrollTarget = window, scroll = window.document, disabled = false, isOverallScroller = true,
|
|||
|
rootTop, rootLeft, rootHeight, scrollBottom, rootBottomTop,
|
|||
|
hasInit = false, curState;
|
|||
|
|
|||
|
function setOptions(options) {
|
|||
|
var _options = options || {};
|
|||
|
_options.offsetBottom && (offsetBottom = _options.offsetBottom);
|
|||
|
_options.scrollTarget && (scrollTarget = _options.scrollTarget);
|
|||
|
_options.scroll && (scroll = _options.scroll);
|
|||
|
_options.disabled !== undefined && (disabled = _options.disabled);
|
|||
|
$scrollTarget = $(scrollTarget);
|
|||
|
isOverallScroller = window.isOverallScroller($scrollTarget[0]);
|
|||
|
$scroll = $(scroll);
|
|||
|
}
|
|||
|
function preCalc() {
|
|||
|
top();
|
|||
|
rootHeight = $root.outerHeight();
|
|||
|
rootTop = $root.offset().top + (isOverallScroller ? 0 : $scrollTarget.scrollTop());
|
|||
|
rootLeft = $root.offset().left;
|
|||
|
}
|
|||
|
function calc(needPreCalc) {
|
|||
|
needPreCalc && preCalc();
|
|||
|
scrollBottom = $scroll.outerHeight() - offsetBottom - rootHeight;
|
|||
|
rootBottomTop = scrollBottom - rootTop;
|
|||
|
}
|
|||
|
function top() {
|
|||
|
if (curState !== 'top') {
|
|||
|
$root.removeClass('fixed').css({
|
|||
|
left: 0,
|
|||
|
top: 0
|
|||
|
});
|
|||
|
curState = 'top';
|
|||
|
}
|
|||
|
}
|
|||
|
function fixed() {
|
|||
|
if (curState !== 'fixed') {
|
|||
|
$root.addClass('fixed').css({
|
|||
|
left: rootLeft + 'px',
|
|||
|
top: 0
|
|||
|
});
|
|||
|
curState = 'fixed';
|
|||
|
}
|
|||
|
}
|
|||
|
function bottom() {
|
|||
|
if (curState !== 'bottom') {
|
|||
|
$root.removeClass('fixed').css({
|
|||
|
left: 0,
|
|||
|
top: rootBottomTop + 'px'
|
|||
|
});
|
|||
|
curState = 'bottom';
|
|||
|
}
|
|||
|
}
|
|||
|
function setState() {
|
|||
|
var scrollTop = $scrollTarget.scrollTop();
|
|||
|
if (scrollTop >= rootTop && scrollTop <= scrollBottom) {
|
|||
|
fixed();
|
|||
|
} else if (scrollTop < rootTop) {
|
|||
|
top();
|
|||
|
} else {
|
|||
|
bottom();
|
|||
|
}
|
|||
|
}
|
|||
|
function init() {
|
|||
|
if(!hasInit) {
|
|||
|
var interval, timeout;
|
|||
|
calc(true); setState();
|
|||
|
// run calc every 100 millisecond
|
|||
|
interval = setInterval(function() {
|
|||
|
calc();
|
|||
|
}, 100);
|
|||
|
timeout = setTimeout(function() {
|
|||
|
clearInterval(interval);
|
|||
|
}, 45000);
|
|||
|
window.pageLoad.then(function() {
|
|||
|
setTimeout(function() {
|
|||
|
clearInterval(interval);
|
|||
|
clearTimeout(timeout);
|
|||
|
}, 3000);
|
|||
|
});
|
|||
|
$scrollTarget.on('scroll', function() {
|
|||
|
disabled || setState();
|
|||
|
});
|
|||
|
$window.on('resize', function() {
|
|||
|
disabled || (calc(true), setState());
|
|||
|
});
|
|||
|
hasInit = true;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
setOptions(options);
|
|||
|
if (!disabled) {
|
|||
|
init();
|
|||
|
}
|
|||
|
$window.on('resize', window.throttle(function() {
|
|||
|
init();
|
|||
|
}, 200));
|
|||
|
return {
|
|||
|
setOptions: setOptions,
|
|||
|
refresh: function() {
|
|||
|
calc(true, { animation: false }); setState();
|
|||
|
}
|
|||
|
};
|
|||
|
}
|
|||
|
$.fn.affix = affix;
|
|||
|
});
|
|||
|
})();
|
|||
|
(function() {
|
|||
|
var SOURCES = window.TEXT_VARIABLES.sources;
|
|||
|
window.Lazyload.js(SOURCES.jquery, function() {
|
|||
|
function toc(options) {
|
|||
|
var $root = this, $window = $(window), $scrollTarget, $scroller, $tocUl = $('<ul class="toc toc--ellipsis"></ul>'), $tocLi, $headings, $activeLast, $activeCur,
|
|||
|
selectors = 'h1,h2,h3', container = 'body', scrollTarget = window, scroller = 'html, body', disabled = false,
|
|||
|
headingsPos, scrolling = false, hasRendered = false, hasInit = false;
|
|||
|
|
|||
|
function setOptions(options) {
|
|||
|
var _options = options || {};
|
|||
|
_options.selectors && (selectors = _options.selectors);
|
|||
|
_options.container && (container = _options.container);
|
|||
|
_options.scrollTarget && (scrollTarget = _options.scrollTarget);
|
|||
|
_options.scroller && (scroller = _options.scroller);
|
|||
|
_options.disabled !== undefined && (disabled = _options.disabled);
|
|||
|
$headings = $(container).find(selectors).filter('[id]');
|
|||
|
$scrollTarget = $(scrollTarget);
|
|||
|
$scroller = $(scroller);
|
|||
|
}
|
|||
|
function calc() {
|
|||
|
headingsPos = [];
|
|||
|
$headings.each(function() {
|
|||
|
headingsPos.push(Math.floor($(this).position().top));
|
|||
|
});
|
|||
|
}
|
|||
|
function setState(element, disabled) {
|
|||
|
var scrollTop = $scrollTarget.scrollTop(), i;
|
|||
|
if (disabled || !headingsPos || headingsPos.length < 1) { return; }
|
|||
|
if (element) {
|
|||
|
$activeCur = element;
|
|||
|
} else {
|
|||
|
for (i = 0; i < headingsPos.length; i++) {
|
|||
|
if (scrollTop >= headingsPos[i]) {
|
|||
|
$activeCur = $tocLi.eq(i);
|
|||
|
} else {
|
|||
|
$activeCur || ($activeCur = $tocLi.eq(i));
|
|||
|
break;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
$activeLast && $activeLast.removeClass('active');
|
|||
|
($activeLast = $activeCur).addClass('active');
|
|||
|
}
|
|||
|
function render() {
|
|||
|
if(!hasRendered) {
|
|||
|
$root.append($tocUl);
|
|||
|
$headings.each(function() {
|
|||
|
var $this = $(this);
|
|||
|
$tocUl.append($('<li></li>').addClass('toc-' + $this.prop('tagName').toLowerCase())
|
|||
|
.append($('<a></a>').text($this.text()).attr('href', '#' + $this.prop('id'))));
|
|||
|
});
|
|||
|
$tocLi = $tocUl.children('li');
|
|||
|
$tocUl.on('click', 'a', function(e) {
|
|||
|
e.preventDefault();
|
|||
|
var $this = $(this);
|
|||
|
scrolling = true;
|
|||
|
setState($this.parent());
|
|||
|
$scroller.scrollToAnchor($this.attr('href'), 400, function() {
|
|||
|
scrolling = false;
|
|||
|
});
|
|||
|
});
|
|||
|
}
|
|||
|
hasRendered = true;
|
|||
|
}
|
|||
|
function init() {
|
|||
|
var interval, timeout;
|
|||
|
if(!hasInit) {
|
|||
|
render(); calc(); setState(null, scrolling);
|
|||
|
// run calc every 100 millisecond
|
|||
|
interval = setInterval(function() {
|
|||
|
calc();
|
|||
|
}, 100);
|
|||
|
timeout = setTimeout(function() {
|
|||
|
clearInterval(interval);
|
|||
|
}, 45000);
|
|||
|
window.pageLoad.then(function() {
|
|||
|
setTimeout(function() {
|
|||
|
clearInterval(interval);
|
|||
|
clearTimeout(timeout);
|
|||
|
}, 3000);
|
|||
|
});
|
|||
|
$scrollTarget.on('scroll', function() {
|
|||
|
disabled || setState(null, scrolling);
|
|||
|
});
|
|||
|
$window.on('resize', window.throttle(function() {
|
|||
|
if (!disabled) {
|
|||
|
render(); calc(); setState(null, scrolling);
|
|||
|
}
|
|||
|
}, 100));
|
|||
|
}
|
|||
|
hasInit = true;
|
|||
|
}
|
|||
|
|
|||
|
setOptions(options);
|
|||
|
if (!disabled) {
|
|||
|
init();
|
|||
|
}
|
|||
|
$window.on('resize', window.throttle(function() {
|
|||
|
init();
|
|||
|
}, 200));
|
|||
|
return {
|
|||
|
setOptions: setOptions
|
|||
|
};
|
|||
|
}
|
|||
|
$.fn.toc = toc;
|
|||
|
});
|
|||
|
})();
|
|||
|
/*(function () {
|
|||
|
|
|||
|
})();*/
|
|||
|
</script><script>
|
|||
|
/* toc must before affix, since affix need to konw toc' height. */(function() {
|
|||
|
var SOURCES = window.TEXT_VARIABLES.sources;
|
|||
|
var TOC_SELECTOR = window.TEXT_VARIABLES.site.toc.selectors;
|
|||
|
window.Lazyload.js(SOURCES.jquery, function() {
|
|||
|
var $window = $(window);
|
|||
|
var $articleContent = $('.js-article-content');
|
|||
|
var $tocRoot = $('.js-toc-root'), $col2 = $('.js-col-aside');
|
|||
|
var toc;
|
|||
|
var tocDisabled = false;
|
|||
|
var hasSidebar = $('.js-page-root').hasClass('layout--page--sidebar');
|
|||
|
var hasToc = $articleContent.find(TOC_SELECTOR).length > 0;
|
|||
|
|
|||
|
function disabled() {
|
|||
|
return $col2.css('display') === 'none' || !hasToc;
|
|||
|
}
|
|||
|
|
|||
|
tocDisabled = disabled();
|
|||
|
|
|||
|
toc = $tocRoot.toc({
|
|||
|
selectors: TOC_SELECTOR,
|
|||
|
container: $articleContent,
|
|||
|
scrollTarget: hasSidebar ? '.js-page-main' : null,
|
|||
|
scroller: hasSidebar ? '.js-page-main' : null,
|
|||
|
disabled: tocDisabled
|
|||
|
});
|
|||
|
|
|||
|
$window.on('resize', window.throttle(function() {
|
|||
|
tocDisabled = disabled();
|
|||
|
toc && toc.setOptions({
|
|||
|
disabled: tocDisabled
|
|||
|
});
|
|||
|
}, 100));
|
|||
|
|
|||
|
});
|
|||
|
})();
|
|||
|
(function() {
|
|||
|
var SOURCES = window.TEXT_VARIABLES.sources;
|
|||
|
window.Lazyload.js(SOURCES.jquery, function() {
|
|||
|
var $window = $(window), $pageFooter = $('.js-page-footer');
|
|||
|
var $pageAside = $('.js-page-aside');
|
|||
|
var affix;
|
|||
|
var tocDisabled = false;
|
|||
|
var hasSidebar = $('.js-page-root').hasClass('layout--page--sidebar');
|
|||
|
|
|||
|
affix = $pageAside.affix({
|
|||
|
offsetBottom: $pageFooter.outerHeight(),
|
|||
|
scrollTarget: hasSidebar ? '.js-page-main' : null,
|
|||
|
scroller: hasSidebar ? '.js-page-main' : null,
|
|||
|
scroll: hasSidebar ? $('.js-page-main').children() : null,
|
|||
|
disabled: tocDisabled
|
|||
|
});
|
|||
|
|
|||
|
$window.on('resize', window.throttle(function() {
|
|||
|
affix && affix.setOptions({
|
|||
|
disabled: tocDisabled
|
|||
|
});
|
|||
|
}, 100));
|
|||
|
|
|||
|
window.pageAsideAffix = affix;
|
|||
|
});
|
|||
|
})();
|
|||
|
</script><!---->
|
|||
|
|
|||
|
</div>
|
|||
|
<script>(function () {
|
|||
|
var $root = document.getElementsByClassName('root')[0];
|
|||
|
if (window.hasEvent('touchstart')) {
|
|||
|
$root.dataset.isTouch = true;
|
|||
|
document.addEventListener('touchstart', function(){}, false);
|
|||
|
}
|
|||
|
})();
|
|||
|
</script>
|
|||
|
</body>
|
|||
|
</html>
|
|||
|
|