Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 19 additions & 11 deletions src/auth.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
import Vue from 'vue';
import eventBus from './global-events';
import { ScreepsAPI } from './scripts/screepsAPI';
import {ScreepsClient} from './scripts/client';
import { ScreepsClient } from './scripts/client';

const DEFAULT_HOST = 'screeps.com';
const DEFAULT_PORT = 443;
Expand All @@ -14,9 +14,10 @@ let auth = new Vue({
host: '',
port: '',
secure: '',
username: '',
token: '',
email: '',
password: '',
authMethod: 'token', // 'token' or 'password'
}
},

Expand All @@ -39,15 +40,17 @@ let auth = new Vue({
host: saved.host,
port: saved.port,
secure: saved.secure,
username: saved.username,
token: saved.token,
email: saved.email,
password: saved.password,
authMethod: saved.authMethod || 'token',
};
} else {
return {
host: DEFAULT_HOST,
secure: DEFAULT_SECURE,
port: DEFAULT_PORT
port: DEFAULT_PORT,
authMethod: 'token'
};
}
},
Expand All @@ -56,18 +59,20 @@ let auth = new Vue({
this.host = saved.host;
this.port = saved.port;
this.secure = saved.secure;
this.username = saved.username;
this.token = saved.token;
this.email = saved.email;
this.password = saved.password;
this.authMethod = saved.authMethod || 'token';
},
save() {
window.localStorage.setItem("saved-credentials", JSON.stringify({
host: this.host,
port: this.port,
secure: this.secure,
username: this.username,
token: this.token,
email: this.email,
password: this.password,
authMethod: this.authMethod,
}))
},
clearSaved() {
Expand All @@ -79,6 +84,7 @@ let auth = new Vue({
if (eventBus.client)
eventBus.client.disconnect();

this.token = token;
let api = new ScreepsAPI({
host: this.host,
port: this.port,
Expand All @@ -87,16 +93,17 @@ let auth = new Vue({
api.token = token;
let client = new ScreepsClient(api);
client.connect().then(() => {
this.save();
eventBus.api = api;
eventBus.client = client;
}).catch(() => {
console.log('error auth connect');
});
},
connect() {
if (!this.username || !this.password) {
if (!this.token && !this.email) {
if (Vue.router.currentRoute.name !== 'login')
Vue.router.replace({name: 'login', query: {backto: Vue.router.currentRoute.path}});
Vue.router.replace({ name: 'login', query: { backto: Vue.router.currentRoute.path } });
return;
}
if (eventBus.api)
Expand All @@ -108,9 +115,12 @@ let auth = new Vue({
host: this.host,
port: this.port,
secure: this.secure,
email: this.username,
email: this.email,
password: this.password,
});
if (this.token) {
api.token = this.token;
}
let client = new ScreepsClient(api);
return client.connect().then(() => {
this.save();
Expand All @@ -131,8 +141,6 @@ let auth = new Vue({
return;
}

if (data.username)
this.username = data.username;
if (data.email)
this.email = data.email;

Expand Down
44 changes: 38 additions & 6 deletions src/pages/Login.vue
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,46 @@
<input id="secure" v-model="auth.secure" type="checkbox" class="form-check-input" />
<label for="secure" class="form-check-label">Secure</label>
</div>

<!-- Authentication method toggle -->
<div class="form-group">
<label for="username">username or email:</label>
<input id="username" v-model="auth.username" class="form-control" />
<label>Authentication Method:</label>
<div class="btn-group btn-group-toggle d-flex" data-toggle="buttons">
<label class="btn btn-outline-primary" :class="{ active: auth.authMethod === 'token' }">
<input type="radio" v-model="auth.authMethod" value="token" /> Token
</label>
<label class="btn btn-outline-primary" :class="{ active: auth.authMethod === 'password' }">
<input type="radio" v-model="auth.authMethod" value="password" /> Username/Password
</label>
</div>
</div>
<div class="form-group">
<label for="password">password:</label>
<input id="password" v-model="auth.password" type="password" class="form-control" />

<!-- Token authentication -->
<div v-if="auth.authMethod === 'token'">
<div class="form-group">
<label for="token">API Token:</label>
<input id="token" v-model="auth.token" type="password" class="form-control" placeholder="Enter your API token" />
<small class="form-text text-muted">
Get your token from <a href="https://screeps.com/a/#!/account/auth-tokens" target="_blank">Account Settings</a> on the Screeps website
</small>
</div>
</div>

<!-- Username/Password authentication -->
<div v-else>
<div class="form-group">
<label for="email">Email:</label>
<input id="email" v-model="auth.email" type="email" class="form-control" placeholder="Enter your email" />
</div>
<div class="form-group">
<label for="password">Password:</label>
<input id="password" v-model="auth.password" type="password" class="form-control" placeholder="Enter your password" />
</div>
<small class="form-text text-muted">
Username/password authentication
</small>
</div>

<div class="text-right">
<button @click.prevent="login()" class="btn btn-primary">Login</button>
</div>
Expand Down Expand Up @@ -62,7 +94,7 @@ export default {
mounted() {
if (this.$route.query.token)
auth.externalConnect(this.$route.query.token);
if (this.$route.query.auto && auth.password)
if (this.$route.query.auto && auth.token)
this.login();

this.$watch(() => eventBus.api, api => {
Expand Down
137 changes: 83 additions & 54 deletions src/scripts/screepsAPI.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,10 @@ export class ScreepsAPI extends EventEmitter {
this.prefix = (opts.secure? 'https' : 'http') + '://' + opts.host + ":" + opts.port
else
this.prefix = opts.ptr ? 'https://screeps.com/ptr' : 'https://screeps.com'

this.token = '';

this.token = opts.token || '';
this.email = opts.email || '';
this.password = opts.password || '';
this.user = null;
this.ws = null;
this.connected = false;
Expand All @@ -45,52 +47,66 @@ export class ScreepsAPI extends EventEmitter {
}

async req(method, path, body) {
if (!this.token && !path.match(/auth/)) {
await this.getToken()
return await this.req(method, path, body);
if (!this.token && !this.email) {
throw new Error('No authentication credentials provided');
}

let res;

try {
res = await this.rawreq(method, path, body);
} catch (e) {
console.log('req err:', e);
if (path.match(/auth/))
throw e;
await this.getToken();
res = await this.rawreq(method, path, body);
}
let res = await this.rawreq(method, path, body);

if (res.status == 200) {
if (res.headers['x-token'])
this.token = res.headers['x-token']
}
if (res.status == 401) {
await this.getToken();
return await this.rawreq(method, path, body);
}
if (res.status == 200) {
if (res.headers['x-token'])
this.token = res.headers['x-token']
}

return res;
return res;
} catch (error) {
if (error.response && error.response.status === 401) {
throw new Error('Unauthorized: Invalid credentials');
}
throw error;
}
}

async basicAuthReq(method, path, body) {
return await axios({
url: this.prefix + path,
json: true,
method,
auth: {
username: this.opts.email,
password: this.opts.password,
},
data: method == 'POST' ? body : undefined || undefined,
params: method == 'GET' ? body : undefined || undefined
});
// Username/password auth for private servers
if (!this.email || !this.password) {
throw new Error('Email and password required for basic authentication');
}

try {
let res = await axios({
url: this.prefix + path,
json: true,
method,
auth: {
username: this.email,
password: this.password
},
data: method == 'POST' ? body : undefined || undefined,
params: method == 'GET' ? body : undefined || undefined
});

if (res.status == 200) {
if (res.headers['x-token'])
this.token = res.headers['x-token']
}

return res;
} catch (error) {
if (error.response && error.response.status === 401) {
throw new Error('Unauthorized: Invalid email or password');
}
throw error;
}
}

connect() {
console.log('connect')
return this.getToken()
if (!this.token && !this.email) {
return Promise.reject(new Error('No credentials provided'));
}
return this.me().then(() => true);
}
disconnect() {
if (this.ws) {
Expand All @@ -101,35 +117,48 @@ export class ScreepsAPI extends EventEmitter {
}
}
auth(email, password) {
this.email = email
this.password = password
return this.getToken()
//(err, token) => cb(null, token !== 'unauthorized')
this.email = email;
this.password = password;
return this.signin();
}
authToken(token) {
this.token = token;
return this.me();
}



async register(username, email, password, serverPassword) {
let res = await this.rawreq('POST', '/api/register/submit', {username, email, password, serverPassword});
return res.data;
}

async getToken() {
console.log('getToken')
let {email, password} = this.opts
let res = await this.req('POST', '/api/auth/signin', {email, password});

if (res.status == 200) {
this.token = res.data.token
return res.data.token;
} else {
throw 'unauthorized';

async signin() {
// Sign in with username/password to get token (for private servers)
if (!this.email || !this.password) {
throw new Error('Email and password required');
}
let res = await this.basicAuthReq('POST', '/api/auth/signin', {
email: this.email,
password: this.password
});
if (res.data.token) {
this.token = res.data.token;
}
this.user = res.data;
return res.data;
}

async me() {
if (!this.token) await this.getToken();
let res = await this.req('GET', '/api/auth/me', null);
if (!this.token && !this.email) {
throw new Error('No credentials provided');
}
// Try token auth first, fall back to basic auth for private servers
let res;
if (this.token) {
res = await this.req('GET', '/api/auth/me', null);
} else {
res = await this.basicAuthReq('GET', '/api/auth/me', null);
}
this.user = res.data;
return res.data;
}
Expand Down